Я хочу задать вопрос, который хочу улучшить частоту кадров. Я отправляю с устройства Android, которое использует предварительный вызов с буфером. Я получаю его на стороне сервера. У меня все хорошо. Частота кадров ужасно медленная. Можете ли вы направить меня. Я делаю преобразование YUV в JPEG на Android тоже, работает нормально, но делает его ужасно медленным
Спасибо
Привет
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) {}
}