15

Hello I am making an android application in which I am using custom camera for recording camera.I am having problem on samsung device.I can not set the profile of Media recorder to CamcorderProfile.get(cameraid, CamcorderProfile.QUALITY_HIGH)

also when try to use

profile = CamcorderProfile.get(cameraid, CamcorderProfile.QUALITY_LOW);
                       profile.videoFrameHeight=360;
                       profile.videoFrameWidth=640;

then my app is working on some devices but crashes on many devices.Any type of help will be appreciable.Thanks in advance please check the code

Camera.Parameters param = mCamera.getParameters();
            param.set( "cam_mode", 1 );  
         // Enable video stabilization. Convenience methods not available in API
            // level <= 14
            String vstabSupported = param.get("video-stabilization-supported");
            if ("true".equals(vstabSupported)) {
                param.set("video-stabilization", "true");
            }
            List<Size> sizes = mCamera.getParameters() .getSupportedVideoSizes();
            mCamera.setParameters( param );
            mMediaRecorder = new MediaRecorder();
            // Step 1: Unlock and set camera to MediaRecorder
            mCamera.unlock();
            mMediaRecorder.setCamera(mCamera);
            mMediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());
            // Step 2: Set sources
            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
            mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
            String deviceMan = android.os.Build.MANUFACTURER;
            Toast.makeText(getApplicationContext(), deviceMan, Toast.LENGTH_SHORT).show();
            // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
            CamcorderProfile profile = CamcorderProfile.get(cameraid, CamcorderProfile.QUALITY_LOW);
//          if(!CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_HIGH)){Log.d("", "the camcorder profile instance is null");
            int currentapiVersion = android.os.Build.VERSION.SDK_INT;
            if (currentapiVersion >= android.os.Build.VERSION_CODES.FROYO){
                // Do something for froyo and above versions
                 boolean tellbol=CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_HIGH);
                 if(deviceMan.equals("samsung")){
                       profile = CamcorderProfile.get(cameraid, CamcorderProfile.QUALITY_LOW);
                       profile.videoFrameHeight=360;
                       profile.videoFrameWidth=640;
                 }
                 else{
                        profile = CamcorderProfile.get(cameraid, CamcorderProfile.QUALITY_HIGH);
                 }
                 mMediaRecorder.setProfile(profile);
            } else{
                // do something for phones running an SDK before froyo
                mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
                mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
//              mMediaRecorder.setVideoSize(720, 480);
                mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
            }

            // Step 4: Set output file
            mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());
            // Step 5: Set the preview output
            // Step 6: Prepare configured MediaRecorder
            try {
                mMediaRecorder.prepare();
            } catch (IllegalStateException e) {
                Log.d("Video", "IllegalStateException preparing MediaRecorder: " + e.getMessage());
                releaseMediaRecorder();
                return false;
            } catch (IOException e) {
                Log.d("Video", "IOException preparing MediaRecorder: " + e.getMessage());
                releaseMediaRecorder();
                return false;
            }
            return true;
Nitin
  • 1,966
  • 4
  • 22
  • 53

2 Answers2

41

This happens because you are requesting the dimensions that you want, but not everycamera is capable of every dimension.

Besides, some devices works with camera aspect ratios slightly diferent, so if you are requesting a rectangle with a wrong ratio, or with a dimensions diferent from the supported, it will crash in some devices.

What to do?

Step 1.

you have to check for the supported sizes. You can do it with

Camera.Parameters p = myCamera.getParameters(); 
List<Size> previewsizes = p.getSupportedPreviewSizes();
List<Size> videosizes = p.getSupportedVideoSizes();

and then, you can choose one. If you want to automatize this, you can go further, and follow the

Step 2

write a function to select the best available size, which will receive the supported sizes, and the desired size, something like:

private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.2;
        double targetRatio = (double) w / h;
        if (sizes == null)
            return null;

        Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        int targetHeight = h;

        // Try to find an size match aspect ratio and size
        for (Size size : sizes) {
            Log.d("Camera", "Checking size " + size.width + "w " + size.height
                    + "h");
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
                continue;
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        // Cannot find the one match the aspect ratio, ignore the
        // requirement
        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }

And the last step, set the parameters

Step 3

private int desiredwidth=640, desiredheight=360; 

Size optimalPreviewSize = getOptimalPreviewSize(previewsizes, desiredwidth, desiredheight);         

Size optimalVideoSize = getOptimalPreviewSize(videosizes, desiredwidth, desiredheight);      

p.setPreviewSize(optimalPreviewSize.width, optimalPreviewSize.height);

 mCamera.unlock();
 mMediaRecorder = new MediaRecorder();
 mMediaRecorder.setCamera(mCamera);

 mMediaRecorder.setVideoSize(optimalVideoSize.width, optimalVideoSize.height);
 myCamera.setParameters(p);

With this, your camera app will work in every device with a camera!

UPDATE

With the getOptimalPreviewSize that i wrote, you get the size whose ratio is closer to the desired, and if none is good enough, you get the one which height is closed to the desired. if you want to give more importante to the size, you can make an easy change, something like

private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
    final double ASPECT_TOLERANCE = 0.2;
    double targetRatio = (double) w / h;
    if (sizes == null)
        return null;

    Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

   if (  you want ratio as closed to what i asked for)
   {  for (Size size : sizes) {
        Log.d("Camera", "Checking size " + size.width + "w " + size.height
                + "h");
        double ratio = (double) size.width / size.height;
        if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
            continue;
        if (Math.abs(size.height - targetHeight) < minDiff) {
            optimalSize = size;
            minDiff = Math.abs(size.height - targetHeight);
        }
    }
   }

   if (you want height as closed to what i asked for) { //you can do other for width
        minDiff = Double.MAX_VALUE;
        for (Size size : sizes) {
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
    }

   if (you want the bigest one) { 
       minDiff = 0;
       for (Size size : sizes) {
           if (  size.height * size.width > minDiff ) {
               optimalSize = size;
               minDiff = size.height * size.width ;
           }
       }
   }
  return optimalSize;
}
Carlos Robles
  • 10,828
  • 3
  • 41
  • 60
  • Thanks for your answer I will try this and let you know if it is working or not – Nitin Dec 06 '13 at 09:17
  • look at the update. you can use getSupportedVideoSizes() instead of the function i told you before, and the rest is as you can imagine... – Carlos Robles Dec 06 '13 at 09:28
  • I had used this method – Nitin Dec 06 '13 at 09:29
  • with the new update should work perfectly, please let me know! – Carlos Robles Dec 06 '13 at 09:31
  • I completed ir. is just using getSupportedVideoSizes() (that in your example you call but never use it result) and then use my function to retrieve the most suitable – Carlos Robles Dec 06 '13 at 09:38
  • do you have any news? – Carlos Robles Dec 06 '13 at 10:19
  • I was teaching android and in an exercise involving camera they had the same problem. Eith this fix all the cameras worked fine in around 20 devices. Of course you can never say EVERY device, but for sure this is a must, and you can be confident it will be good for a wide sort of devices – Carlos Robles Dec 08 '13 at 01:42
  • Hello Carlos it is working but i want the biggest videoframe it is showing the smallest frame which is possible with setting the profile to Low .But it is not acceptable by the client. – Nitin Dec 10 '13 at 11:47
  • 3
    its funny that i dont get the full reward for an ansewr that is finally working. If you get the smallest frame is since the smallest is the one whose ratio is closer to the desired. if you want to give more importante to the size, you can make an easy change. I will be back with that in one minute – Carlos Robles Dec 10 '13 at 11:55
  • i updated the answer. you have to complete the ifs with variables you create, or just remove the part of the code you dont need – Carlos Robles Dec 10 '13 at 12:11
  • Hello carlos i know you are a good programmer.If i do not get answer.I will accept your answer because it is very close to what i want +1 for that.I will use your code and will optimize it. Thanks :) – Nitin Dec 10 '13 at 14:40
  • thanks for the good words. with the update i write you should be able to automatically use the biggest available size. – Carlos Robles Dec 10 '13 at 14:51
  • Great answer. Still such a frustrating situation, a particular device i was using wasn't even outputting a stack trace – Joe Maher Dec 07 '15 at 03:30
  • u have saved my time :) thnx – Muhammad Umair Shafique Feb 18 '16 at 10:19
0

With using the parameters you can set the video preview width and height..

        Camera.Parameters param = camera.getParameters();

        param.setPreviewSize("your width"
                "your height");
        camera.setParameters(param);
kalyan pvs
  • 14,486
  • 4
  • 41
  • 59