简体   繁体   中英

Android Preveiw Frame Rate Query

I want to ask a question that I want to improve my frame rate. I am sending from android Device which is using Preview call with Buffer. I am than receiving it on the Server side. Ia m getting everything fine. The frame rate is terribly slow. Can you please guide me. I am doing the YUV to JPEG conversion on Android too, working fine but its making it terribly slow

Thanks

Regards

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.hardware.Camera;
import android.hardware.Camera.ErrorCallback;
import android.hardware.Camera.Size;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.Camera.PreviewCallback;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.Toast;
import android.app.Service;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.net.Uri;
import android.os.IBinder;
import android.provider.MediaStore;
import android.view.LayoutInflater;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.net.InetAddress;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.List;

import android.widget.TextView;

public class SdfJuliaActivity extends Activity implements SensorEventListener
{
    private static String TAG = "SDFJulia";

    /*
     * WiFi Methods
     * ------------
     * Please do not delete any method, just adjust them if necessary.
     * 
     * Problems:
     * - if server is not available / running and app tries to connect,
     *      it crashes the emulator. Works fine on smartphone, though.
     * 
     */

    protected static  DataOutputStream os;
    protected static Socket socket;
    private static String address = "192.168.2.102:4444";           //also default IP address
    private static String ipAddress;
    private static int port;

    //Connect to given ip address on given port
    protected static boolean connect(String serverName, int port)
    {
        Log.d(TAG, "Connecting to " + serverName + ":" + port);

        try
        {
            socket = new Socket(serverName,port);       
            os = new DataOutputStream(socket.getOutputStream());
        }
        catch (UnknownHostException e)
        {
            Log.d(TAG, "Unknown Host Exception while connecting: " + e);
            return false;
        }
        catch (IOException e)
        {
            Log.d(TAG, "IO Exception while connecting: " + e);
            return false;
        }

        if (!socket.isConnected()) { return false; }

        return true;
    }

    //Close the current connection
    protected static void disconnect()
    {   
        if (!socket.isClosed())
        {
            try { socket.close(); }
            catch (IOException e) {}
        }
    }

    //Check if we are connected
    protected static boolean connected()
    {
        //Check if socket is open
        if (socket.isClosed())
        {   return false;   }

        //Check if socket is actually connected to a remote host
        if (!socket.isConnected())
        {   return false;   }

        //We are connected!
        return true;
    }

    //Send a single frame to the server
    //YUV-Image
    protected static void sendFrame(byte[] data)
    {   
        //Check if a frame is actually available
        if (data != null)
        {
            try
            {       
                os.writeInt(data.length);
                os.write(data, 0, data.length);         
                os.flush();
            }
            catch (IOException e) {};
        }
    }

    //Send all sensor data to the server
    protected static void sendData()
    {
        try
        {
            os.writeFloat(orientation_x);
            os.writeFloat(orientation_y);
            os.writeFloat(orientation_z);
            os.writeDouble(gps_longitude);
            os.writeDouble(gps_latitude);
            os.writeDouble(gps_altitude);
        }
        catch (IOException e) {};
    }

    public static String getAddress()
    {   return address; };

    /*
     * Sensor Stuff
     * ------------
     */

    SensorManager sensorManager = null;
    private static float accelerometer_x;
    private static float accelerometer_y;
    private static float accelerometer_z;

    private static float orientation_x;
    private static float orientation_y;
    private static float orientation_z; 


    //New sensor data available
    public void onSensorChanged(SensorEvent event)
    {
        synchronized (this)
        {
            switch (event.sensor.getType())
            {
                case Sensor.TYPE_ACCELEROMETER:
                    accelerometer_x = event.values[0];
                    accelerometer_y = event.values[1];
                    accelerometer_z = event.values[2];
                    break;

                case Sensor.TYPE_ORIENTATION:
                    orientation_x = event.values[0];
                    orientation_y = event.values[1];
                    orientation_z = event.values[2];
                    break;                  
            }
        }
    }

    //Sensor accuracy has changed (unused)
    public void onAccuracyChanged(Sensor sensor, int accuracy) {}

    private static double gps_latitude;
    private static double gps_longitude;
    private static double gps_altitude;
    private static long gps_lastfix;

    /*
     * Camera Methods
     * --------------
     * 
     */

    private Camera mCamera;
    SurfaceView mPreview;

    private void startVideo()
    {
        SurfaceHolder videoCaptureViewHolder = null;

        try { mCamera = Camera.open(); }
        catch (Exception e) { Log.d(TAG,"Can not open camera. In use?"); };

        mCamera.setErrorCallback
        (
            new ErrorCallback()
            {   public void onError(int error, Camera camera) {}    }
        );

        Camera.Parameters parameters = mCamera.getParameters();

        final int previewWidth = parameters.getPreviewSize().width;
        final int previewHeight = parameters.getPreviewSize().height;

        parameters.setPreviewFrameRate(30);
        mCamera.setParameters(parameters);

        parameters = mCamera.getParameters();
        Log.d(TAG,"Format: " + parameters.getPreviewFormat());
        Log.d(TAG,"FPS: " + parameters.getPreviewFrameRate());        

        if (null != mPreview)
        {   videoCaptureViewHolder = mPreview.getHolder();  }


        try { mCamera.setPreviewDisplay(videoCaptureViewHolder); }
        catch (Throwable t) {}

        //Get Preview Size to set the data buffers to it 
        Size previewSize=mCamera.getParameters().getPreviewSize();
        //Set the Buffer Size according to Preview Size
        int dataBufferSize=(int)(previewSize.height*previewSize.width*
                               (ImageFormat.getBitsPerPixel(mCamera.getParameters().getPreviewFormat())/8.0));

        mCamera.addCallbackBuffer(new byte[dataBufferSize]);
        mCamera.addCallbackBuffer(new byte[dataBufferSize]);
        mCamera.addCallbackBuffer(new byte[dataBufferSize]);
        //This method is called for every preview frame
        //we use it to transmit both the current preview frame as well as the sensor data
        mCamera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback()
        {
            int fpsCount = 0;
            boolean test = true;


            public void onPreviewFrame(byte[] data, Camera camera)
            {
                //Check if connection is present; if not, try to reconnect
                if (!connected())
                {   connect(ipAddress, port);   }
                else
                {
                    //Prediction step XXX

                    //Log.d(TAG, "Transmitting data.");

                    //Convert image to YUV
                    /*YuvImage image = new YuvImage(data,ImageFormat.NV21,previewWidth,previewHeight,null);
                    Rect rect = new Rect(0,0,previewWidth,previewHeight);
                    ByteArrayOutputStream oas = new ByteArrayOutputStream();
                    image.compressToJpeg(rect,100,oas);
                    byte[] imageJPG = oas.toByteArray();*/

                    //if (test)
                    //{ Log.d(TAG,"Length: " + imageJPG.length);    test = false;   };

                    //Send the current frame to the server
                    sendFrame(data);

                    //Send the corresponding sensor data to the server
                    sendData();

                    camera.addCallbackBuffer(data);

                }
            }
        });

        try { mCamera.startPreview(); }
        catch (Throwable e)
        {
            mCamera.release();
            mCamera = null;
            return;
        }
    }

    private void stopVideo() 
    {
        if (mCamera == null)
        { return; }

        try
        {
            mCamera.stopPreview();
            mCamera.setPreviewDisplay(null);
            mCamera.setPreviewCallback(null);
            mCamera.release();
        }
        catch (IOException e)
        {
            e.printStackTrace();
            return;
        }

        mCamera = null;
    }   

    /* Input Validation
     * ----------------
     */

    //Check if user specified address is valid 
    private static boolean checkAddress(String userinput)
    {
        String [] part = userinput.split("\\:");

        if (part.length != 2)
        {   return false;   }

        if (!validIP(part[0]))
        {   return false;   }

        int i = Integer.parseInt(part[1]);
        if (i < 1 || i > 10000)
        {   return false;   }

        return true;
    }

    //Check for valid IP address
    private static boolean validIP (String userinput)
    {
        String [] part = userinput.split("\\.");

        if (part.length != 4)
        {
            Log.d(TAG,"Invalid ip address length.");
            return false;
        }

        for (String s : part)
        {
            int i = Integer.parseInt(s);
            if (i < 0 || i > 255)
            {   
                Log.d(TAG,"Invalid ip address values.");
                return false;
            }
        }

        return true;
    }    

    /*
     * Activity Creation
     * -----------------
     */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        //Always use portrait view
        //Otherwise activity gets destroyed when orientation is changed --> network & video stream is lost
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        setContentView(R.layout.main);        

        socket = new Socket();

        /*
         * Sensors
         * -------
         * This registers our app to receive the latest sensor data.
         */            

        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);       
        sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), sensorManager.SENSOR_DELAY_FASTEST);
        sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), sensorManager.SENSOR_DELAY_FASTEST);

        /*
         * GPS
         * ---
         * This registers our app to receive the latest GPS data.
         */        

        LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
        LocationListener locationListener = new LocationListener()
        {
            public void onLocationChanged(Location location)
            {
                gps_latitude = location.getLatitude();
                gps_longitude = location.getLongitude();
                gps_altitude = location.getAltitude();
                gps_lastfix = System.currentTimeMillis();
            }

            public void onStatusChanged(String provider, int status, Bundle extras) {}
            public void onProviderEnabled(String provider) {}
            public void onProviderDisabled(String provider) {}
        };

        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);        

        final Button serviceButton = (Button) findViewById(R.id.btn_serviceButton);
        final EditText ipText = (EditText) findViewById(R.id.text_ipAddress);
        ipText.setText(address);

        //CameraStuff here first
        mPreview = (SurfaceView) findViewById(R.id.cameraView);

        SurfaceHolder videoCaptureViewHolder = mPreview.getHolder();
        videoCaptureViewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        videoCaptureViewHolder.addCallback(new Callback()
        {
            public void surfaceDestroyed(SurfaceHolder holder) { stopVideo(); }
            public void surfaceCreated(SurfaceHolder holder) {}
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
        });

        //Click Listener for Button
        //starts & stops the service
        serviceButton.setOnClickListener(new View.OnClickListener()
        {
            public void onClick(View v)
            {
                if (connected())
                {
                    Toast.makeText(getApplicationContext(), "Connection terminated.", Toast.LENGTH_SHORT).show();
                    serviceButton.setText("Connect");

                    //Stop the app
                    stopVideo();                //Stop video & sending data
                    disconnect();               //Stop network services
                }
                else
                {
                    address = ipText.getText().toString();
                    String [] part = ipText.getText().toString().split("\\:");

                    //Validate input
                    ipAddress = part[0];
                    port = Integer.parseInt(part[1]);
                    //int port = 4444;

                    if (!checkAddress(address))
                    {
                        //Invalid ip address specified
                        Toast.makeText(getApplicationContext(), "Invalid address specified.", Toast.LENGTH_SHORT).show();
                        Log.d(TAG,"Invalid address specified.");                
                    }
                    else
                    {
                        if (!connect(ipAddress, port))
                        {
                            //Connection failed
                            Toast.makeText(getApplicationContext(), "Could not connect.", Toast.LENGTH_SHORT).show();
                            Log.d(TAG,"Could not connect.");
                        }
                        else
                        {
                            //Connection successful
                            Log.d(TAG,"Connected.");
                            Toast.makeText(getApplicationContext(), "Connection successful.", Toast.LENGTH_SHORT).show();
                            serviceButton.setText("Disconnect");

                            //Start video & sending data
                            startVideo();
                        }
                    }
                }
            }
        });
    }

    //Don't do anything if configuration is changed (e.g. phone has been rotated)
    @Override
    public void onConfigurationChanged(Configuration newConfig) {}
}
  1. You must call getSupportedPreviewFpsRange() of com.android.hardware.Camera, and you will get a list of FPS range supported
  2. Select the proper one and call setSupportedPreviewFpsRange()
  3. all that must be called before startPreview() call.

you can refer to SDK guide.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM