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.
Related
This is coded in NativeScript, so I'll try my best to adapt the scenario to Java. I have created an in-app video view with support to record the video.
This is done as follows:
First I create a SurfaceView that will hold the preview of the camera:
this.mSurfaceView = new android.view.SurfaceView(this._context);
this.mHolder = this.mSurfaceView.getHolder();
this.mHolder.setType(android.view.SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
Then I create an instance of the Camera, and sets the video surface:
var mCamera = android.hardware.Camera;
var camera = mCamera.open(1);
this.camera = camera;
this.camera.setDisplayOrientation(90);
var parameters = camera.getParameters();
parameters.setRecordingHint(true);
if( parameters.isVideoStabilizationSupported() ){
parameters.setVideoStabilization(true);
}
camera.setParameters(parameters);
this.camera.setPreviewDisplay(_this.mHolder);
this.camera.startPreview();
this.camera.startFaceDetection();
Now, all is good. I have the camera preview in the view that I want it to be. The color is good and I think the image aspect ratio is good too.
However, when I initiate the recording, as I do with the following code:
this.mediarecorder = new android.media.MediaRecorder();
// Step 1: Unlock and set camera to MediaRecorder
this.camera.unlock();
this.mediarecorder.setCamera(this.camera);
// Step 2: Set sources
this.mediarecorder.setAudioSource(android.media.MediaRecorder.AudioSource.CAMCORDER);
this.mediarecorder.setVideoSource(android.media.MediaRecorder.VideoSource.CAMERA);
//this.mediarecorder.setOutputFormat(android.media.MediaRecorder.OutputFormat.MPEG_4);
// Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
this.mediarecorder.setProfile(android.media.CamcorderProfile.get(android.media.CamcorderProfile.QUALITY_HIGH));
// platform.screen.mainScreen.widthDIPs
// platform.screen.mainScreen.heightDIPs
// Step 4: Set output file
var fileName = "videoCapture_" + new Date() + ".mp4";
var path = android.os.Environment.getExternalStoragePublicDirectory(android.os.Environment.DIRECTORY_DCIM).getAbsolutePath() + "/Camera/" + fileName;
this.file = new java.io.File(path);
this.mediarecorder.setOutputFile(this.file.toString());
this.mediarecorder.setOrientationHint(270);
try {
this.mediarecorder.prepare();
this.mediarecorder.start();
} catch( ex ) {
console.log(ex);
}
Then, the image suddenly becomes darker, and my face (its what's in focus when I'm trying it out) gets wider. So the aspect ratio changes, and so does the lighting somehow.
I have tried setting setPictureSize on the camera parameters, and setVideoSize on the MediaRecorder with no luck. And for the lighting change, I have simply no clue as to whats going on. Now I've been googling myself half way to heaven, and still found nothing, so I hope someone here has got any tip on what to pursue next?
Video recording generally tries to run at a steady frame rate, such as 30fps. Camera preview often slows itself down to 10-15fps to maintain brightness, so if you're in a darker location, video recording will be darker (since it can't expose for longer than 1/30s instead of 1/10s that camera preview can).
Did you call setVideoSize before or after calling setProfile? The setProfile call changes many parameters, including preview size; most video recording sizes are 16:9, and the default camera preview resolution is likely a 4:3 size. So when you start the recording, the aspect ratio switches.
Most video recording apps use 16:9 preview sizes even before starting recording so that they're consistent. You can also record 4:3 video, but that's generally not what people want to see.
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.
I am using media recorder to record video in an android app.
mMediaRecorder.setCamera(mServiceCamera);
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
//mMediaRecorder.setVideoSize(mPreviewSize.width, mPreviewSize.height);
mMediaRecorder.setVideoFrameRate(30);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
String file_name = Environment.getExternalStorageDirectory().getPath() +"/myVideo.mp4";
mMediaRecorder.setOutputFile(file_name);
mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
mMediaRecorder.prepare();
mMediaRecorder.start();
The problem is in the line
mMediaRecorder.setVideoSize(mPreviewSize.width, mPreviewSize.height);
In HTC and Xperia, setVideoSize works fine (Will work only if I don't comment this line).
But in Nexus and Note, setVideoSize won't work( Will work only if I comment this line).
What should I do in order for the app to run in all these devices correctly??
You need to understand that the preview and the actual captured video are two different things, likewise Preview sizes and Video sizes are two different parameters. What you see in the viewfinder is essentially the preview, but it is not what actually gets recorded.
When starting a camera, you set the preview size to the camera. But you must query for the supported preview sizes and should set one among them.
Camera camera = camera.open();
List psizes = camera.getParameters()
.getSupportedPreviewSizes();
Once you have set up the preview, you can start recording by using a MediaRecorder, and the video size can be set to the media recorder, and it is the actual size of the video that will be captured.
Again, you should set one of supported video size.
List sizes = camera.getParameters()
.getSupportedVideoSizes();
and then, you can set one of these to the media recorder
mediaRecorder.setVideoSize(videoWidth, videoHeight);
So, remember to check for the supported sizes always, else you are bound to get an app crash.
Video sizes in a device is equal to preview sizes. You have to first check whether video size you setting is available or not. Video sizes in different devices may be diffrent.so,first check available preview sizes using getSupportedPreviewSizes () and then set video size. this will return a list.you have to select only one of them.
I've tried several answer I've found across the web, such as:
Camera.Parameters parameters = mCamera.getParameters();
parameters.set("camera-id", 2);
mCamera.setParameters(parameters);
or
mMediaRecorder.setVideoSource(2);
But it doesn't work. I've also set permissions on the manifest file:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
Am i missing out on something? I've searched StackOverflow and I know this has been asked before but there seem to be no confirmed solution on this, any kind of help would be appreciated.
Note: I'm using Galaxy S on the 2.1 platform
Anyway after a few trials and error, I figured it out how to do it:
Camera.Parameters parameters = mCamera.getParameters();
parameters.set("camera-id", 2);
parameters.setPreviewSize(640, 480); // or (800,480) this is supported front camera preview size # Samsung Galaxy S
mCamera.setParameters(parameters);
Or, if you need to use it with MediaRecorder:
MediaRecorder mMediaRecorder = new MediaRecorder();
Camera mCamera = Camere.open();
Camera.Parameters parameters = mCamera.getParameters();
parameters.set("camera-id", 2);
parameters.setPreviewSize(640, 480); // or (800,480)
mCamera.setParameters(parameters);
mCamera.unlock(); // unlock, to give other process to access it otherwise it can't be used later
mMediaRecorder.setCamera(mCamera);
// continue with mMediaRecorder standard routines here
If you need to have a smaller preview size, you could set/scale down your SurfaceView size instead.
There currently isn't a standard API for front-facing cameras; you will need to rely on whatever (if any) documentation the hardware manufacturer has for using their extensions to access the front-facing camera. This will of course only work on those specific devices.
Note writing raw strings like "camera-id" is often a good sign you have wandered into the woods outside of the official SDK. :)
I think this is as good a place as any to add some details I've worked out.
In case you're using the front facing camera in portrait mode and the resulting file comes out cut up into squares with green blocks thrown in try inverting the width and height (both preview and recorder) and setting the encoder to H263...
This solved the problem on my Samsung Galaxy S on 2.3.3+...
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