I am trying to create a custom camera app. I followed the Android Developer example from here with minor tweaks. However, my camera preview turns out to be rather dark. On the other hand, the stock camera gives a much brighter preview.
I have tried several settings to make it work better but it seems none of them are having any impact. Relevant code is posted here.
CameraActivity (Main)
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
if(CameraHelper.checkCameraHardware(this)) {
mHelper = new CameraHelper(this, getWindowManager().getDefaultDisplay());
}
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
mPreview = new CameraPreview(this, CameraHelper.camera);
mPreview.setLayoutParams(new LayoutParams(CameraHelper.mSize.width, CameraHelper.mSize.height, Gravity.CENTER));
preview.addView(mPreview);
}
CameraHelper class (initialize the camera and set the default parameters)
public CameraHelper(CameraListener listener, Display display){
mListener = listener;
camera = getCameraInstance();
mParameters = camera.getParameters();
initCameraParameters();
mSize = getPreviewSize(display);
mParameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);
mParameters.setPictureSize(2560, 1920);
mParameters.setAutoExposureLock(false);
mParameters.setAutoWhiteBalanceLock(false);
mParameters.set("iso", "ISO800"); //Tried with 400, 800, 600 (values obtained from flatten())
mParameters.setColorEffect("none");
mParameters.setPictureSize(2560, 1920);
mParameters.setPreviewFrameRate(20);
mParameters.set("scene-mode", "auto");
mParameters.setFocusMode("auto");
mParameters.setExposureCompensation(4);
camera.setParameters(mParameters);
}
The Camera sends the frames to SurfaceHolder.Surface from the example linked from developer pages above.
See the difference here:
Stock Camera App
My Camera App
Tried setting the ISO, etc based on upack parameters from the camera as posted here. It still didn't work.
Parameters(16369):
effect-values=none,mono,negative,sepia,aqua,sharpen,purple,green-tint,blue-tint,pink,yellow,red-tint,mono,antique;exposure-compensation-step=0.5;focal-length=3.43;focus-areas=(0,0,0,0,0);focus-distances=0.10,1.20,Infinity;focus-mode-values=auto,macro,facedetect;gps-altitude=0;gps-latitude=0;gps-longitude=0;gps-processing-method=GPS;gps-timestamp=0;horizontal-view-angle=51.2;iso=auto;iso-values=auto,ISO50,ISO100,ISO200,ISO400,ISO800,ISO1600;jpeg-quality=1;jpeg-thumbnail-height=480;jpeg-thumbnail-size-values=640x480,0x0;jpeg-thumbnail-width=640;max-exposure-compensation=4;max-num-focus-areas=1;max-zoom=12;min-exposure-compensation=-4;picture-format=jpeg;picture-format-values=jpeg;picture-size-values=2560x1920,2560x1536,2048x1536,2048x1232,1600x1200,1600x960,800x480,640x480;preview-format=yuv420sp;preview-format-values=yuv420sp;preview-fps-range=15000,30000;preview-fps-range-values=(15000,30000);preview-frame-rate=30;preview-frame-rate-values=30;preview-size=640x480;preview-size-values=1280x720,800x480,720x480,640x480,352x288;rotation=0;scene-mode=auto;scene-mode-values=auto,portrait,landscape,night,beach,snow,sunset,fireworks,sports,party,candlelight,asd,backlight,dusk-dawn,text,fall-color;vertical-view-angle=39.4;video-frame-format=yuv422i-yuyv;whitebalance-values=auto,incandescent,fluorescent,daylight,cloudy-daylight;zoom=0;zoom-ratios=100,125,150,175,200,225,250,275,300,325,350,375,400;zoom-supported=true;focus-mode=auto;picture-size=2560x1920;exposure-compensation=4;
Edit: Upon further testing based on comments below, it appears that its just the preview that is turning out darker than it should be. The actual captured image is well lit and exposure compensatiion seems to be working fine. Its just the preview that is giving me a headache. Tested on i9003 running CM11 and Nexus 10 running stock android.
There appears to be a bug with certain cameras reporting the supported preview FPS range incorrectly. You can identify the offending devices by those that return the same value for min and max when calling
getPreviewFpsRange (int[] range)
In my case I saw this issue with devices that reported (15000, 15000) and (30000, 30000), but not with devices where the values were different, like (7000, 30000).
The best solution I could find was to identify the supported FPS range that had different values for min and max, and set that:
Camera.Parameters params = camera.getParameters();
final int[] previewFpsRange = new int[2];
params.getPreviewFpsRange(previewFpsRange);
if (previewFpsRange[0] == previewFpsRange[1]) {
final List<int[]> supportedFpsRanges = params.getSupportedPreviewFpsRange();
for (int[] range : supportedFpsRanges) {
if (range[0] != range[1]) {
params.setPreviewFpsRange(range[0], range[1]);
break;
}
}
}
camera.setParameters(params);
This works because the ranges reported seem to only have 1 item with the actual range. Eg:
BLU Vivo XL:
preview-fps-range=30000,30000
preview-fps-range-values=(15000,15000),(20000,20000),(24000,24000),(5000,30000),(30000,30000)
Pixel:
preview-fps-range=7000,30000
preview-fps-range-values=(15000,15000),(24000,24000),(7000,30000),(30000,30000)
A more robust approach would be to set the min and max by comparing all those available.
In addition to the previous answers, this can happen with Camera2 if you are doing
createCaptureRequest(CameraDevice.TEMPLATE_RECORD)
change to
createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
UPDATE: I have also begun to see a dark preview on some newer Pixel devices and this happens if you don't set the fps in the capture request or if you set the fps to something that the device can't handle BUT not on Samsung devices like the Note 10 and S10
From my experiments, scene-mode setting can change the preview (unlike ISO or exposure-compensation, which both work for captured pictures). Don't use auto. Try scene-mode-values=night or scene-mode=dusk-dawn.
The problem with scenes is that the supported values are not standardized across devices. But some kind of night is usually present.
Related
After implementing the camera2 API for the inApp camera I noticed that on Samsung devices the images appear blurry. After searching about that I found the Sasmung Camera SDK (http://developer.samsung.com/galaxy#camera). So after implementing the SDK on Samsung Galaxy S7 the images are fine now, but on Galaxy S6 they are still blurry. Someone experienced those kind of issues with Samsung devices?
EDIT:
To complement #rcsumners comment. I am setting autofocus by using
mPreviewBuilder.set(SCaptureRequest.CONTROL_AF_TRIGGER, SCaptureRequest.CONTROL_AF_TRIGGER_START);
mSCameraSession.capture(mPreviewBuilder.build(), new SCameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(SCameraCaptureSession session, SCaptureRequest request, STotalCaptureResult result) {
isAFTriggered = true;
}
}, mBackgroundHandler);
It is a long exposure image where the use has to take an image of a static non moving object. For this I am using the CONTROL_AF_MODE_MACRO
mCaptureBuilder.set(SCaptureRequest.CONTROL_AF_MODE, SCaptureRequest.CONTROL_AF_MODE_MACRO);
and also I am enabling auto flash if it is available
requestBuilder.set(SCaptureRequest.CONTROL_AE_MODE,
SCaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
I am not really an expert in this API, I mostly followed the SDK example app.
There could be a number of issues causing this problem. One prominent one is the dimensions of your output image
I ran Camera2 API and the preview is clear, but the output was quite blurry
val characteristics: CameraCharacteristics? = cameraManager.getCameraCharacteristics(cameraId)
val size = characteristics?.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)?.getOutputSizes(ImageFormat.JPEG) // The issue
val width = imageDimension.width
val height = imageDimension.height
if (size != null) {
width = size[0].width; height = size[0].height
}
val imageReader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 5)
The code below was returning a dimension about 245*144 which was way to small to be sent to the image reader. Some how the output was stretching the image making it end up been blurry. Therefore I removed this line below.
val size = characteristics?.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)?.getOutputSizes(ImageFormat.JPEG) // this was returning a small
Setting the width and height manually resolved the issue.
You're setting the AF trigger for one frame, but then are you waiting for AF to complete? For AF_MODE_MACRO (are you verifying the device lists support for this AF mode?) you need to wait for AF_STATE_FOCUSED_LOCKED before the image is guaranteed to be stable and sharp. (You may also receive NOT_FOCUSED_LOCKED if the AF algorithm can't reach sharp focus, which could be because the object is just too close for the lens, or the scene is too confusing)
On most modern devices, it's recommended to use CONTINUOUS_PICTURE and not worry about AF triggering unless you really want to lock focus for some time period. In that mode, the device will continuously try to focus to the best of its ability. I'm not sure all that many devices support MACRO, to begin with.
A week ago I've started researching the Android camera API. I have successfully inited the camera and started preview, and it worked fine. Then I've found out I wasn't initializing and releasing the camera properly, so I overhauled the code somewhat, and now I have a problem that didn't occur initially: extremely low FPS. About 0.5, that's 2 seconds per frame. Interestingly enough, I get 1 frame with a delay, and then a second frame immediately after (1-15 ms), followed again by 2 seconds delay before the next frame.
This is my camera initialization code:
m_openedCamera = Camera.open(id);
m_surfaceHolder = new SurfaceView(MyApplication.instance().getApplicationContext()).getHolder();
Assert.assertNotNull(m_openedCamera);
// This is required on A500 for some reason
Camera.Parameters params = m_openedCamera.getParameters();
params.setPreviewFormat(ImageFormat.NV21);
params.setPreviewSize(320, 240);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH)
{
params.setRecordingHint(true);
params.setAutoExposureLock(true);
params.setAutoWhiteBalanceLock(true);
}
m_openedCamera.setParameters(params);
int bitsPerPx = ImageFormat.getBitsPerPixel(ImageFormat.NV21);
int width = params.getPreviewSize().width;
int height = params.getPreviewSize().height;
int size = (int)(width * height * bitsPerPx / 8.0);
m_openedCamera.addCallbackBuffer( new byte[size] );
m_openedCamera.addCallbackBuffer( new byte[size] );
m_openedCamera.addCallbackBuffer( new byte[size] );
m_openedCamera.addCallbackBuffer( new byte[size] );
m_openedCamera.setErrorCallback(this);
m_openedCamera.setPreviewDisplay(m_surfaceHolder);
m_openedCameraFacing = facing;
m_openedCamera.setPreviewCallback(this);
m_openedCamera.startPreview();
I have just added callback buffers - hasn't changed anything. In my initial code from a week ago I had no surface view, but removing it now has no effect either.
This occurs on my second, much newer tablet as well, even though FPS is higher there (8-10), and there's no double frame there, the frames are spaced evenly. The FPS used to be at least 20. Light conditions haven't changed between now and then, btw.
Update: tried opening the camera in a separate thread as described here - no change.
params.setRecordingHint(true); is used to start video record starts.
Please check it again with "params.setRecordingHint(false)"
Please make your own previewcallbak function and then
private PreviewCallback mPreviewCallback = new PreviewCallback();
....
setPreviewCallback(mPreviewCallback);
Regarding PreviewCallback(), you can refer to CameraTest.Java in cts directory : cts/tests/tests/hawdware/src/android/hardware/cts
From your comment below
"I have successfully inited the camera and started preview, and it worked fine. Then I've found out I wasn't initializing and releasing the camera properly"
I guess you was using the default camera parameters defined in camera HAL at first. Although it is not clear what "initializing" means, I think they is likely camera parameters setting.
So, I'd like to suggest you remove the code for params and then test it again.
Or, you can test it one by one
Remove only "params.setPreviewSize(320, 240);"
Remove only "params.setPreviewFormat(ImageFormat.NV21);"
Remove both 1 and 2.
I am writing an app that sets the flash mode to torch. I have been testing the application on my Droid X, and the LED light does not come on. I tried it on a Droid Incredible and it worked fine. I can't figure out what the problem is. Here is part of my code for turning on torch mode.
Camera mCamera = Camera.open();
Camera.Parameters params = mCamera.getParameters();
if(params.getFlashMode() != null){
params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
}
mCamera.setParameters(params);
I have added mCamera.startPreview(); because I read that should make a difference, but it doesn't. I also made a list of available flash modes and displayed them to the screen to make sure that my Droid X does have torch mode, and it was in the list. I even created a new application from code I found online that turns the LED flash on and off with a button. Again it worked fine on the Droid Incredible but not the Droid X. Is there something I am missing to get this to run on the Droid X, or could it be something with Gingerbread? The Droid X is running Gingerbread and the Droid Incredible is running FroYo.
There are quite a few quirks when setting FLASH_MODE_TORCH.
Often you need to start a camera preview:
Camera mCamera = Camera.open();
mCamera.startPreview();
Camera.Parameters params = mCamera.getParameters();
if(params.getFlashMode() != null){
params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
}
mCamera.setParameters(params);
That may resolve it on some phones, other phones also require the preview to be drawn to a SurfaceView. This can be done by implementing SurfaceHolder.Callback interface in your activity.
See an example here.
It could be that the Droid X doesn't support Torch Mode. Try something like this:
List<String> pList = camera.getParameters().getSupportedFlashModes();
if (pList.contains(Parameters.FLASH_MODE_TORCH))
parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(parameters);
Refer to Issue 191453:
SurfaceTexture mDummy = new SurfaceTexture(1); // any int argument will do
camera.setPreviewTexture(mDummy);
camera.startPreview();
The only thing I found that works on the Droid X is the code presented by Siddhpura Amit part way down the page in this answer Use camera flashlight in Android. He checks the manufacturer and checks to see if it contains the string "motorola." If so, he has special code that can switch the camera Flash LED on or off. I can verify that it does work as I have a Motorola Droid X.
Can android MediaRecorder capture video with resolution higher than 320*240?
When I used MediaRecorder::setVideoSize() to set the video size, the captured video were all at the resolution of 320*240. Whats even worse, the higher ones can not get a clear video, they were somehow greenish. (encoder used is h263, format is mpeg4)
Android version used here is 1.6
Could you please anyone help me out?
I had an issue similar to what is described here. I turned out that I had to restructure my code slightly before I could adjust the video size.
The important thing is that setVideoSize() is called before setVideoEncoder(). I can't find this in the documentation, however it solved my problems with setting a specific video resolution.
Also keep in mind that setOutputFormat() should be called before setVideoSize().
As as side note the same is true for setVideoFrameRate(). If it is not called before setVideoEncoder() it will not have any affect.
This was tested with Android 2.3.3
Here is a code example:
recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setVideoSize(640,480);
recorder.setVideoFrameRate(30);
recorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
First you are going to want to determine what your Camera supports. Try:
List<String> anti = params.getSupportedAntibanding();
List<String> color = params.getSupportedColorEffects();
List<String> focus = params.getSupportedFocusModes();
List<String> flash = params.getSupportedFlashModes();
List<Size> previewSize = params.getSupportedPreviewSizes();
List<Size> sizes = params.getSupportedPictureSizes();
List<Integer> frameRates = params.getSupportedPreviewFrameRates();
List<Integer> pictureFormats = params.getSupportedPictureFormats();
List<String> scene = params.getSupportedSceneModes();
List<String> white = params.getSupportedWhiteBalance();
This will tell you all of the Camera's supported parameters. Second Make sure that you initialize your MediaRecorder properly see the google documentation for the order in which you need to set the MediaRecorder. Also, if your Camera.setPreviewSize and MediaRecorder.setVideoSize are different it can cause odd behavior.
I'm trying to record video from the Camera using the MediaRecorder. Here's a code snippet
snip..
mr.setAudioSource( MediaRecorder.AudioSource.MIC );
mr.setVideoSource( MediaRecorder.VideoSource.CAMERA);
mr.setOutputFormat( MediaRecorder.OutputFormat.THREE_GPP );
mr.setAudioEncoder( MediaRecorder.AudioEncoder.AMR_NB );
mr.setVideoEncoder( MediaRecorder.VideoEncoder.MPEG_4_SP );
mr.setVideoSize( 200, 200 );
mr.setVideoFrameRate( 15 );
..snap
Code executes on a MileStone/Droid, non-empty output file will be created. But when I try to view the video, it looks like this:
My first thoughts were about some sort of encoding error, so I tried every possible OutputFormat/VideoEncoder combination, with no effetcs on the result.
LogCat shows the following error
CameraInput: Unsupported parameter(x-pvmf/media-input-node/cap-config-interface;valtype=key_specific_value)
But I can't figure out, what I may have set wrong. I used camera.getParameters(), set the preview size with the returned params and then pushed them back using camera.setParameters()...
Worked thru every piece of sample code I could find, but still found no solution.
Does anyone have any ideas ?
you must set the correct setVideoSize( x, y) function.
you must call the function which give you the size options , and choose from that list
when camera open,
Camera.Parameters p = mCamera.getParameters();
p.setPreviewSize(mSur.getWidth(), mSur.getHeight());
mCamera.setParameters(p);
and when you prepareRecord
mCamera.unlock();
if (mRecorder == null) {
mRecorder = new MediaRecorder();
} else {
mRecorder.reset();
}
mNextRecordFileName = getOneFileName();
mRecorder.setCamera(mCamera);
mRecorder.setVideoSource(mVideoSource);
mRecorder.setAudioSource(mAudioSource);
mRecorder.setPreviewDisplay(mSur.getHolder().getSurface());
mRecorder.setOutputFormat(mVideoFormat);
//设置在setEncoder之前才有效,如果不设置,htc会崩溃掉
mRecorder.setVideoSize(this.mSur.getWidth(), mSur.getHeight());
Log.i(TAG, this.mSur.getHolder().getSurfaceFrame().height()+"gao");
Log.i(TAG, this.mSur.getHolder().getSurfaceFrame().width()+"kuan");
Log.i(TAG, "宽"+this.mSur.getWidth()+"高"+mSur.getHeight());
mRecorder.setVideoEncoder(mVideoEncoder);
mRecorder.setAudioEncoder(mAudioEncoder);
mRecorder.setOutputFile(mNextRecordFileName);
hope it can help you
To avoid distortion in recorded video ( I have seen this on Galaxy S3) make sure you set camera parameter preview size and mediarecorder videosize to same height and width.
To get supported camera preview size:
Camera.Parameters parameters = camera.getParameters();
List<Camera.Size> list = parameters.getSupportedPreviewSizes();
parameters.setPreviewSize(list.get(X).width, list.get(X).height);
// If you set Width and Height not supported by device you will get exception
// MediaRecorder object mMediaRecoder
mMediaRecoder.setVideoSize(list.get(X).width, list.get(X).height);
Hey,
I know you posted this a while ago and I doubt your still looking for an answer but I thought this might help someone else out.
I think your problem is mr.setVideoSize( 200, 200 );
I doubt the phones camera supports a 1X1 capture resolution. It is better to use something like mr.setVideoSize(Camcorder.get(Camcorder.QUALITY_LOW).videoFrameWidth,Camcorder.get(Camcorder.QUALITY_LOW).videoFrameHeight);
That will ensure that the resolution is supported by the camera. Also make sure your preview resolution matches your camera resolution, or that can cause the same problem. I know it happens to me if I have my preview set to QUALITY_HIGH and my camera to QUALITY_LOW