0

I am just curious about correctly using setOneShotPreview() callback and correctly using onPreviewFrame(byte[] data, Camera camera) to get an image as it is displayed in preview. I have implemented all the code and its working but the resulting image is of no use. Below is my code please help me with what i am doing wrong.

    public class MainActivity extends ActionBarActivity {
private static final String TAG = "CamTestActivity";
Preview preview;
Button buttonClick;
Camera camera;
String fileName;
Activity act;
Context ctx;
int frontCamera;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ctx = this;
    act = this;
    //requestWindowFeature(Window.FEATURE_NO_TITLE);
    //getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

    setContentView(R.layout.activity_main);

    preview = new Preview(this, (SurfaceView)findViewById(R.id.surfaceView));
    preview.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
    ((FrameLayout) findViewById(R.id.preview)).addView(preview);
    preview.setKeepScreenOn(true);
    frontCamera = findFrontFacingCamera();
    buttonClick = (Button) findViewById(R.id.button_capture);
    //camera.setOneShotPreviewCallback(cameraPreviewCallback);

    buttonClick.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            //camera.setOneShotPreviewCallback(cameraPreviewCallback);
            //camera.takePicture(shutterCallback, rawCallback, jpegCallback);
            camera.setOneShotPreviewCallback(new Camera.PreviewCallback() {

                @Override
                public void onPreviewFrame(byte[] data, Camera camera) {
                    // TODO Auto-generated method stub
                       Camera.Parameters parameters = camera.getParameters();
                        int format = parameters.getPreviewFormat();
                        //YUV formats require more conversion
                        if (format == ImageFormat.NV21 || format == ImageFormat.YUY2 || format == ImageFormat.NV16) {
                            int w = parameters.getPreviewSize().width;
                            int h = parameters.getPreviewSize().height;
                            Log.d("imageFormat",Integer.toString(format));
                            Log.d("imageNV21",Integer.toString(ImageFormat.NV21));
                            Log.d("imageYUY2",Integer.toString(ImageFormat.YUY2));
                            Log.d("imageNV16",Integer.toString(ImageFormat.NV16));
                            // Get the YuV image
                            YuvImage yuv_image = new YuvImage(data, format, w, h, null);
                            // Convert YuV to Jpeg
                            Rect rect = new Rect(0, 0, w, h);
                            ByteArrayOutputStream output_stream = new ByteArrayOutputStream();
                            yuv_image.compressToJpeg(rect, 100, output_stream);
                            byte[] byt = output_stream.toByteArray();
                            FileOutputStream outStream = null;


                            try {
                                // Write to SD Card
                                File folder = new File(Environment.getExternalStorageDirectory().toString()+"/SilentCamera/Images");
                              if(folder.exists()){
                                  Log.d("creating folder","Folder already exists");
                                  //Save the path as a string value
                                  String extStorageDirectory = folder.toString();
                                  Log.d("DirPath",extStorageDirectory);
                                  fileName = String.format(extStorageDirectory+"/%d.jpg", System.currentTimeMillis());
                                  Log.d("ImagePath",fileName);
                                  outStream = new FileOutputStream(fileName);

                                //Uri uriSavedImage = Uri.fromFile(file);

                                outStream.write(byt);
                                outStream.flush();
                                outStream.close();
                                Log.d("SilentCam","Frame Received");
                              }
                             else{
                              folder.mkdirs();
                              String extStorageDirectory = folder.toString();
                              Log.d("DirPath",extStorageDirectory);
                              fileName = String.format(extStorageDirectory+"/%d.jpg", System.currentTimeMillis());
                              Log.d("ImagePath",fileName);
                              outStream = new FileOutputStream(fileName);
                                outStream.write(byt);
                                outStream.close();
                                Log.d("PassMainCamera", "onPictureTaken - wrote bytes: " + data.length);

                                Log.d("ImageUrl","Image Url added to database");
                          }
                            } catch (FileNotFoundException e) {
                                e.printStackTrace();
                            } catch (IOException e) {
                                e.printStackTrace();
                            } finally {
                            }
                }
                }
            });
            //camera.startPreview();
        }
    });


}

@Override
protected void onResume() {
    super.onResume();
    camera = Camera.open(frontCamera);
    camera.startPreview();
    preview.setCamera(camera);
    resetCam();
}

@Override
protected void onPause() {
    if(camera != null) {
        camera.stopPreview();
        preview.setCamera(null);
        camera.release();
        camera = null;
    }
    super.onPause();
}

private void resetCam() {
    camera.startPreview();
    preview.setCamera(camera);
}


 public static void setCameraDisplayOrientation(Context context,
            int cameraId, android.hardware.Camera camera)
    {

        int result = MainActivity.getCameraDisplayOrientation(context, cameraId, camera);

        if (android.os.Build.VERSION.SDK_INT <= 14)
        {
            camera.stopPreview();
            camera.setDisplayOrientation(result);
            camera.startPreview();

            Log.i("Version<=14","inSettingOrirntation");
        } else
        {
            camera.setDisplayOrientation(90);
            Log.i("Version>14","inSettingOrirntation");
       }

    }// end setCameraDisplayOrientation

 public static int getCameraDisplayOrientation(Context context,
            int cameraId, android.hardware.Camera camera)
    {
        android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
        android.hardware.Camera.getCameraInfo(cameraId, info);
        int rotation = ((Activity) context).getWindowManager().getDefaultDisplay()
                .getRotation();
        int degrees = 0;
        switch (rotation)
        {
        case Surface.ROTATION_0:
            degrees = 0;
            break;
        case Surface.ROTATION_90:
            degrees = 90;
            break;
        case Surface.ROTATION_180:
            degrees = 180;
            break;
        case Surface.ROTATION_270:
            degrees = 270;
            break;
        }

        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
        {
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360; // compensate the mirror
        } else
        { // back-facing
            result = (info.orientation - degrees + 360) % 360;
        }

        return result;
    }
 // frinding id of front facing camera
 private int findFrontFacingCamera() {
        int foundId = -1;
        int numCams = Camera.getNumberOfCameras();
        for (int camId = 0; camId < numCams; camId++) {
            CameraInfo info = new CameraInfo();
            Camera.getCameraInfo(camId, info);
            if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
                foundId = camId;
                break;
            }
        }
        return foundId;
    }

}

And this is my surface holder implementation,,

    class Preview extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "Preview";

SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
private Activity activity;
Context context;
Preview(Context _context, SurfaceView sv) {
    super(_context);
    context = _context;



    mSurfaceView = sv;
    mHolder = mSurfaceView.getHolder();
    mHolder.addCallback(this);
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

public void setCamera(Camera camera) {
    mCamera = camera;
    if (mCamera != null) {
        mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
        requestLayout();

    Camera.Parameters params = mCamera.getParameters();

        List<String> focusModes = params.getSupportedFocusModes();
        if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
            params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
            mCamera.setParameters(params);

        }
    }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
    final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
    setMeasuredDimension(width, height);

    if (mSupportedPreviewSizes != null) {
        mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
    }
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    if (changed && getChildCount() > 0) {
        final View child = getChildAt(0);

        final int width = r - l;
        final int height = b - t;

        int previewWidth = width;
        int previewHeight = height;
        if (mPreviewSize != null) {
            previewWidth = mPreviewSize.width;
            previewHeight = mPreviewSize.height;
        }

        if (width * previewHeight > height * previewWidth) {
            final int scaledChildWidth = previewWidth * height / previewHeight;
            child.layout((width - scaledChildWidth) / 2, 0,
                    (width + scaledChildWidth) / 2, height);
        } else {
            final int scaledChildHeight = previewHeight * width / previewWidth;
            child.layout(0, (height - scaledChildHeight) / 2,
                    width, (height + scaledChildHeight) / 2);
        }
    }
}

public void surfaceCreated(SurfaceHolder holder) {
    try {
        if (mCamera != null) {
            mCamera.setPreviewDisplay(holder);
           // mCamera.startPreview();

        }
    } catch (IOException exception) {
        Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
    }
}

public void surfaceDestroyed(SurfaceHolder holder) {
    if (mCamera != null) {
       // mCamera.stopPreview();
    }
}


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

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    if(mCamera != null) {
        Camera.Parameters parameters = mCamera.getParameters();
        String sceneMode = "SCENE_MODE_PORTRAIT";
        parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
        parameters.setPictureSize(mPreviewSize.width, mPreviewSize.height);
        Log.d("Preview Width",Integer.toString(mPreviewSize.width));
        Log.d("Preview Height",Integer.toString(mPreviewSize.height));
        Log.d("Preview Zoom",Integer.toString(parameters.getZoom()));
        //parameters.setSceneMode(sceneMode);
        //parameters.se
        requestLayout();
        //MainActivity.setCameraDisplayOrientation(context,Camera.CameraInfo.CAMERA_FACING_FRONT, mCamera);

        mCamera.setParameters(parameters);
        //mCamera.startPreview();
        //mCamera.setDisplayOrientation(90);
    }
}

}

This is all my code,,, Its been 3 days and still stuck at this problem,,,, every one says its working but not with me,,, i am testing it on samsung galaxy s with android 2.3.6 gingerbread,,,, please help me Thanks.

Farooq
  • 90
  • 9
  • What image format and frame size do you receive from camera? – Alex Cohn Mar 25 '15 at 21:00
  • default image format NV21 and i then convert it to .jpg – Farooq Mar 26 '15 at 20:17
  • But what is the frame size? Is it the same as you chose in `parameters.setPreviewSize()`? On some devices, the list reported by `getSupportedPreviewSizes()` is not reliable. – Alex Cohn Mar 27 '15 at 20:58
  • One more possible problem: if you use the camera in portrait orientation, you still need to set the preview size as in landscape (e.g. width=800 height=480), and same is true for the data received by the callback (set orientation only effects the way the preview is displayed on screen). – Alex Cohn Mar 27 '15 at 21:04
  • Yes it is the same as in parameters.setPreviewSize(),,, thanks for your help i will try this – Farooq Mar 28 '15 at 11:30

1 Answers1

1

This is because the data provided as parameter is not in jpeg format. You need to convert it first:

Camera.Parameters parameters = camera.getParameters();
final int format = parameters.getPreviewFormat();
YuvImage im = new YuvImage( data, format, width, height, null );
ByteArrayOutputStream out = new ByteArrayOutputStream();
final Rect rect = new Rect( 0, 0, width, height );
im.compressToJpeg( rect, 100, out );
byte[] jpeg = out.toByteArray();
Teemu Lätti
  • 121
  • 1
  • 5
  • Thanks Teemu Latti, i have updated the code in my question and have tried your way but still unable to get the expected result – Farooq Mar 26 '15 at 10:52
  • What is the problem? Is the image having no data, or is it corrupt? – Teemu Lätti Mar 26 '15 at 11:02
  • I tried your exact code from above and I got a valid JPEG image from the camera. Are you starting the preview by calling camera.startPreview()? – Teemu Lätti Mar 26 '15 at 11:19
  • the picture i am getting is very noisy,, sometimes green color scattered over all the image – Farooq Mar 26 '15 at 20:04
  • yes i am starting the preview by calling camera.startPreview(),,,, ok i am adding the full code for camera implementation, please take a look at the code in the question – Farooq Mar 26 '15 at 20:13
  • The symptom suggests the problem has something to do with incorrect format of the data. Please check this question and answers http://stackoverflow.com/questions/17682345/how-to-get-android-camera-preview-data Maybe you need to call setPreviewFormat() and/or setPreviewSize() in your device as suggested in the answers. Interesting problem because it works on my phone... – Teemu Lätti Mar 27 '15 at 11:42
  • I think so, can you give me the preview class where surface view is created and camera parameters are set,,, i am stuck at this problem.... here is my preview class code please take a look and correct me – Farooq Mar 27 '15 at 19:41