Question

I've try to implement an custom Video recorder by using surfaceview with start stop . This video recorder works fine. The problem is the quality of the video is very poor. When i record 10 sec video from default camera it is nearly 12MB. But when i use my code it is only 300KB and poor quality. Any suggestion for improve the quality of the video.

My sample source code

In xml :

<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <SurfaceView
        android:id="@+id/surface_camera"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/buttonstart"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="Start" 
            android:layout_weight="1"/>

        <Button
            android:id="@+id/buttonstop"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="Stop"
            android:layout_weight="1" />
    </LinearLayout>

    <Chronometer
        android:id="@+id/chronometer1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/linearLayout1"
        android:layout_marginLeft="45dp"
        android:text="Chronometer"
        android:textSize="25sp"
       android:textStyle="bold|italic"
       android:typeface="monospace"
       android:background="#025076"
        />

</RelativeLayout>

In java class:

    public MediaRecorder mrec = new MediaRecorder();
    private Camera mCamera;
        protected void startRecording() throws IOException {
                recording = true;
                mrec = new MediaRecorder(); // Works well
                // myChronometer.stop();
                mCamera.unlock();
                mrec.setCamera(mCamera);

                mrec.setVideoSource(MediaRecorder.VideoSource.CAMERA);
                mrec.setAudioSource(MediaRecorder.AudioSource.MIC);

                mrec.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);

                // mrec.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
                // mrec.setPreviewDisplay(surfaceHolder.getSurface());

                mrec.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
                mrec.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);

                // mCamera.getParameters().getSupportedVideoSizes().get(0);

                mrec.setVideoFrameRate(30);
                mrec.setVideoSize(1280, 720);
//Just i've try different bitrate
                mrec.setVideoEncodingBitRate(100000000);
                // mrec.setMaxDuration(10000);
                mrec.setPreviewDisplay(surfaceHolder.getSurface());

//output_path is file path
                mrec.setOutputFile(output_path);
                // mrec.setMaxDuration(10000);
                mrec.prepare();
                mrec.start();

            } 

There is any more suggestion for improve the quality.

Was it helpful?

Solution

I just using the following code for improving the quality of video. This is little bit better for me

 protected void startRecording() {
        try {
            recording = true;
            mrec = new MediaRecorder();
            mCamera.unlock();
            mrec.setCamera(mCamera);

            //Set audio source
            mrec.setAudioSource(MediaRecorder.AudioSource.MIC);
            //set video source
            mrec.setVideoSource(MediaRecorder.VideoSource.CAMERA);

            //set output format
            mrec.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);

            int width = 320;
            int height = 240;
            try {
                //get the available sizes of the video
                List<Size> tmpList = getSupportedVideoSizes();

                final List<Size> sizeList = new Vector<Size>();

                // compare the apsect ratio of the candidate sizes against the
                // real ratio
                Double aspectRatio = (Double.valueOf(getWindowManager()
                        .getDefaultDisplay().getHeight()) / getWindowManager()
                        .getDefaultDisplay().getWidth());
                for (int i = tmpList.size() - 1; i > 0; i--) {
                    Double tmpRatio = Double.valueOf(tmpList.get(i).height)
                            / tmpList.get(i).width;
                    if (EnableLog.LOG_TAG) {
                        Log.e("Width & height", tmpList.get(i).width + " x "
                                + tmpList.get(i).height);
                    }
                    if (Math.abs(aspectRatio - tmpRatio) < .15) {
                        width = tmpList.get(i).width;
                        height = tmpList.get(i).height;
                        sizeList.add(tmpList.get(i));
                    }
                }
                if (EnableLog.LOG_TAG) {
                    Log.e("tmpList", tmpList + "*");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (EnableLog.LOG_TAG) {
                Log.e("set width and height", width + " x " + height);
            }
            // set the size of video.
            // If the size is not applicable then throw the media recorder stop
            // -19 error
            mrec.setVideoSize(width, height);

            // Set the video encoding bit rate this changes for the high, low.
            // medium quality devices
            mrec.setVideoEncodingBitRate(1700000);

            //Set the video frame rate
            mrec.setVideoFrameRate(30);

            //set audio encoder format
            mrec.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);

            //set video encoder format
            mrec.setVideoEncoder(MediaRecorder.VideoEncoder.H264);

            //Show the display preview
            mrec.setPreviewDisplay(surfaceHolder.getSurface());

            //output file path
            mrec.setOutputFile(output_path);

            mrec.prepare();

            mrec.start();

        } catch (IllegalStateException e) {
            Crashlytics.logException(e);
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

And need this too:

public List<Size> getSupportedVideoSizes() {
        if (params.getSupportedVideoSizes() != null) {
            return params.getSupportedVideoSizes();
        } else {
            // Video sizes may be null, which indicates that all the supported
            // preview sizes are supported for video recording.
            return params.getSupportedPreviewSizes();
        }
    }

I hope it will help someone. Thanks.

OTHER TIPS

Edited :

@Override
 public void surfaceCreated(SurfaceHolder arg0) {
  camera = openFrontFacingCamera();
  if (camera != null) {
   try {
    camera.setPreviewDisplay(holder);
   } catch (IOException e) {
    camera.release();
    camera = null;
   }
  } else {
   Toast.makeText(act, "Problem in opening Camera.", Toast.LENGTH_LONG)
     .show();
   act.finish();
  }
 }



@Override
 public void surfaceChanged(SurfaceHolder arg0, int format, int height,
   int width) {
  Camera.Size previewSize = null;

  try {
   Camera.Parameters parameters = camera.getParameters();
   List<Camera.Size> supportSize = parameters
     .getSupportedPreviewSizes();
   if (supportSize != null) {
    previewSize = getOptimalPreviewSize(supportSize, width, height);
   }
   parameters.setPreviewSize(previewSize.width, previewSize.height);
   parameters.set("orientation", "portrait");
   camera.setPreviewDisplay(arg0);
   camera.setParameters(parameters);
   camera.startPreview();
   camera.unlock();
   mRecorder.setPreviewDisplay(arg0.getSurface());
   mRecorder.setCamera(camera);
   mRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
   mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
   mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
   mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
   mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
   mRecorder.setMaxDuration(90000);
   mRecorder.setOnInfoListener(oninfoLis);
   mRecorder.setVideoSize(previewSize.width, previewSize.height);
   mRecorder.setVideoFrameRate(30);

   mRecorder.setVideoEncodingBitRate(500);
   mRecorder.setAudioEncodingBitRate(128);
   mRecorder.setOutputFile("/mnt/sdcard/myfile"
     + SystemClock.elapsedRealtime() + ".mp4");
   mRecorder.prepare();
   mRecorder.start();
  } catch (IllegalStateException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  } catch (Exception e) {
   e.getMessage();
  }
 } 


private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
  final double ASPECT_TOLERANCE = 0.1;
  double targetRatio = (double) w / h;
  if (sizes == null)
   return null;
  Size optimalSize = null;
  double minDiff = Double.MAX_VALUE;
  int targetHeight = h;
  for (Size size : sizes) {
   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 (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;
 }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top