我是android编程的新手,我正在尝试将视频收集为mp4文件和传感器数据,并将其写入dat文件。 我已设法开始录制但停止录制会冻结应用程序。 分为两个阶段。
第一阶段: SurfaceView用于将传感器读数作为文本叠加到视频输入上。 SurfaceView在UI线程上运行,而传感器日志记录和MediaRecorder在不同的线程上运行。 根据需要生成相机预览。
第二阶段: 现在我尝试开始录制,并将带有时间戳的相关传感器数据写入文件。 我正在使用Media Recorder来实现这一目标。当我试图停止录制整个程序挂起。 在调试模式下,代码不会冻结在mediaRecorder.stop()但生成的mp4文件已损坏,我无法使用视频播放器(VLC)打开它。
根据需要记录传感器读数。此外,即使我没有记录传感器值,视频录制也不起作用。
有人可以帮我解决这个问题吗?
主要活动:
package priyaman.com.glassdatavisualizer;
import com.google.android.glass.media.Sounds;
import com.google.android.glass.touchpad.Gesture;
import com.google.android.glass.touchpad.GestureDetector;
import com.google.android.glass.widget.CardBuilder;
import com.google.android.glass.widget.CardScrollAdapter;
import com.google.android.glass.widget.CardScrollView;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.hardware.Camera;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import priyaman.com.glassdatavisualizer.controllers.CameraController;
import priyaman.com.glassdatavisualizer.controllers.DrawViewController;
import priyaman.com.glassdatavisualizer.controllers.SensorController;
import priyaman.com.glassdatavisualizer.controllers.SensorThread;
import priyaman.com.glassdatavisualizer.service.MotionSensorService;
import priyaman.com.glassdatavisualizer.utilities.CameraUtils;
public class GlassVisualizerActivity extends Activity {
private Camera camera;
private CameraController cameraController;
private GestureDetector mGestureDetector;
private SensorController sensorController;
private SensorThread sensorThread = null;
private DrawViewController drawView;
FrameLayout alParent;
public GestureDetector createGestureDetector(final Context context)
{
GestureDetector gestureDetector = new GestureDetector(context);
//Create a base listener for generic gestures
gestureDetector.setBaseListener( new GestureDetector.BaseListener() {
@Override
public boolean onGesture(Gesture gesture) {
if(priyaman.com.glassdatavisualizer.utilities.Log.D) priyaman.com.glassdatavisualizer.utilities.Log.d("gesture = " + gesture);
if (gesture == Gesture.TAP) {
cameraController.releaseCamera();
if(cameraController.isRecording){
cameraController.stopRecordingThread.run();//recordThread.run();
cameraController = new CameraController(context,camera);
}else{
cameraController.recordThread.run();//startRecording();
}
return true;
} else if (gesture == Gesture.TWO_TAP) {
//handleGestureTwoTap();
//doStopService();
return true;
}
return false;
}
});
return gestureDetector;
}
@Override
protected void onCreate(Bundle bundle) {
Log.d("Debug:", "onCreate: GlassVisualizerActivity");
super.onCreate(bundle);
camera = CameraUtils.getCameraInstance();
Camera.Parameters params = camera.getParameters();
params.setRecordingHint(true);
camera.setParameters(params);
cameraController = new CameraController(this, camera);
//this.setContentView(cameraController);
mGestureDetector = this.createGestureDetector(this);
drawView = new DrawViewController(this,cameraController);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
if (cameraController != null){
alParent = new FrameLayout(this);
alParent.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.FILL_PARENT,
FrameLayout.LayoutParams.FILL_PARENT));
//doStartService();
alParent.addView(cameraController);
alParent.addView(drawView);
this.setContentView(alParent);
//sensorController = new SensorController(this,drawView);
sensorThread = new SensorThread(this,drawView);
sensorThread.run();
}
}
@Override
protected void onResume() {
super.onResume();
if (cameraController != null) {
cameraController.releaseCamera();
}
//doStartService();
// Set the view
//alParent.addView(drawView);
//alParent.addView(cameraController);
this.setContentView(alParent);
}
@Override
public boolean onGenericMotionEvent(MotionEvent event)
{
if (mGestureDetector != null) {
return mGestureDetector.onMotionEvent(event);
}
return false;
}
@Override
protected void onPause() {
if (cameraController != null) {
cameraController.releaseMediaRecorder(); // if you are using MediaRecorder, release it first
cameraController.releaseCamera(); // release the camera immediately on pause event
}
super.onPause();
}
}
绘制SurfaceView:
package priyaman.com.glassdatavisualizer.controllers;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import priyaman.com.glassdatavisualizer.utilities.Log;
import priyaman.com.glassdatavisualizer.utilities.Utilities;
/**
* Created by priya_000 on 5/20/2015.
*/
public class DrawViewController extends SurfaceView implements SurfaceHolder.Callback{
private Paint textPaint = new Paint();
public SurfaceHolder surfaceHolder = null;
private Context context = null;
private CameraController cameraController = null;
public DrawViewController(Context context, CameraController cameraController) {
super(context);
this.context = context;
textPaint = new Paint();
textPaint.setARGB(255, 200, 0, 0);
textPaint.setTextSize(20);
setWillNotDraw(false);
surfaceHolder = getHolder();
this.cameraController = cameraController;
}
@Override
protected void onDraw(Canvas canvas){
String content = "";
int counter = 50;
if(Utilities.logSensorValues){
canvas.drawText("Recording:",50,20,textPaint);
}
if(Utilities.lastSensorValuesAccelerometer != null) {
content += "Accelerometer:\n" + Utilities.lastSensorValuesAccelerometer.toString() + "\n";
canvas.drawText("Accelerometer:\n" + Utilities.lastSensorValuesAccelerometer.toString(), 50, counter+=25, textPaint);
}
if(Utilities.lastSensorValuesGravity != null) {
content += "Gravity:\n" + Utilities.lastSensorValuesGravity.toString() + "\n";
canvas.drawText("Gravity:\n" + Utilities.lastSensorValuesGravity.toString() , 50, counter+=25, textPaint);
}
if(Utilities.lastSensorValuesLinearAcceleration != null) {
content += "Linear Acceleration:\n" + Utilities.lastSensorValuesLinearAcceleration.toString() + "\n";
canvas.drawText( "Linear Acceleration:\n" + Utilities.lastSensorValuesLinearAcceleration.toString() , 50, counter+=25, textPaint);
}
if(Utilities.lastSensorValuesGyroscope != null) {
content += "Gyroscope:\n" + Utilities.lastSensorValuesGyroscope.toString() + "\n";
canvas.drawText( "Gyroscope:\n" + Utilities.lastSensorValuesGyroscope.toString() , 50, counter+=25, textPaint);
}
if(Utilities.lastSensorValuesRotationVector != null) {
content += "Rotation Vector:\n" + Utilities.lastSensorValuesRotationVector.toString() + "\n";
canvas.drawText( "Rotation Vector:\n" + Utilities.lastSensorValuesRotationVector.toString() , 50, counter+=25, textPaint);
}
Log.d("Values Published:" + content);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Canvas c = holder.lockCanvas();
if(c!=null)
draw(c);
if(c!=null)
holder.unlockCanvasAndPost(c);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Canvas c = holder.lockCanvas();
if(c!=null)
draw(c);
if(c!=null)
holder.unlockCanvasAndPost(c);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
cameraController.releaseCamera();
}
}
相机相关SurfaceView:
package priyaman.com.glassdatavisualizer.controllers;
import android.content.Context;
import android.graphics.Rect;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import priyaman.com.glassdatavisualizer.utilities.Log;
import android.os.Handler;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import priyaman.com.glassdatavisualizer.R;
import priyaman.com.glassdatavisualizer.utilities.CameraUtils;
import priyaman.com.glassdatavisualizer.utilities.Utilities;
/**
* Created by priya_000 on 5/19/2015.
*/
public class CameraController extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder finalView;
private Camera camera;
private MediaRecorder mediaRecorder;
public boolean isRecording = false;
public RecThread recordThread = null;
public StopRecordingThread stopRecordingThread = null;
public CameraController(Context context, Camera camera){
super(context);
Log.d("In Camera Controller Constructor");
this.camera = camera;
finalView = getHolder();
finalView.addCallback(this);
finalView.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mediaRecorder = new MediaRecorder();
recordThread = new RecThread(mediaRecorder);
stopRecordingThread = new StopRecordingThread((mediaRecorder));
}
public void surfaceCreated(SurfaceHolder holder) {
Log.v("In create surface");
try {
if(camera==null){
camera = CameraUtils.getCameraInstance();
if(camera == null)
return;
//setMeteringParams();
}
camera.setPreviewDisplay(holder);
} catch (IOException e1) {
Log.e("Error in surface creation",e1);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
//Log that camera controller destroyed
Log.d("In surface destroyed:Camera Controller Destroyed");
if(camera!= null)
camera.stopPreview();
releaseCamera();
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h){
Log.d("In Surface Changed");
if (holder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
camera.stopPreview();
} catch (Exception e){
}
try {
//setMeteringParams();
camera.setPreviewDisplay(holder);
camera.startPreview();
} catch (Exception e){
}
}
public class RecThread implements Runnable{
MediaRecorder mediaRecorder = null;
public RecThread(MediaRecorder mediaRecorder){
this.mediaRecorder = mediaRecorder;
}
public void run(){
startRecording();
}
public boolean prepareVideoRecorder(){
Log.d("Preparing Video Recorder");
try {
if (camera == null) {
camera = CameraUtils.getCameraInstance();
}
camera.unlock();
//mediaRecorder = new MediaRecorder();
mediaRecorder.setCamera(camera);
//mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
try {
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
}catch(Exception e){
Log.e("Exception caught in setting profile");
e.printStackTrace();
}
//mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
//mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mediaRecorder.setPreviewDisplay(finalView.getSurface());
File outputFile = CameraUtils.getOutputMediaFile(CameraUtils.MEDIA_TYPE_VIDEO);
Utilities.sensorFileName = outputFile.getName();
Utilities.logSensorValues = true;
mediaRecorder.setOutputFile(outputFile.toString());
try {
mediaRecorder.prepare();
} catch (IllegalStateException e) {
Log.d("IllegalStateException preparing MediaRecorder: " + e.getMessage());
releaseMediaRecorder();
return false;
} catch (IOException e) {
Log.d("IOException preparing MediaRecorder: " + e.getMessage());
releaseMediaRecorder();
return false;
}
//return true;
}catch(Exception e){
Log.e("Error in prepare Video Recorder",e);
e.printStackTrace();
return false;
}finally{
//this.releaseCamera();
//Log.d("Camera released");
//return false;
Log.d("In finally block");
}
return true;
}
public void startRecording(){
Log.d("In Start Recording");
Log.d("Camera is :" + String.valueOf(camera==null));
if(isRecording){
Log.i("Stopping Recording");
Utilities.logSensorValues = false;
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
Log.i("Sleeping for 1 sec after stopping recording");
}
}, 1000);
mediaRecorder.stop();
Log.i("Video Stored@");
releaseMediaRecorder();
try {
//camera.reconnect();
//camera.lock();
if(camera == null){
camera = CameraUtils.getCameraInstance();
}
camera.setPreviewDisplay(getHolder());
camera.lock();
camera.startPreview();
}catch(Exception e){
Log.e("Preview display on setpreview after release media recotrdr",e);
}
isRecording = false;
}else{
if(prepareVideoRecorder()){
mediaRecorder.start();
Log.i("Started Recording");
isRecording = true;
}
}
}
}
public void releaseMediaRecorder(){
if (mediaRecorder != null) {
mediaRecorder.reset(); // clear recorder configuration
mediaRecorder.release(); // release the recorder object
//mediaRecorder = null; //Not setting it to null as it is required for reuse
/* try {
camera.lock(); // lock camera for later use
}catch(Exception e){
e.printStackTrace();
}*/
}
}
public void releaseCamera(){
if (camera != null){
camera.release(); // release the camera for other applications
camera = null;
}
}
public class StopRecordingThread implements Runnable{
MediaRecorder mediaRecorder = null;
public StopRecordingThread(MediaRecorder mediaRecorder){
this.mediaRecorder = mediaRecorder;
}
public void run(){
Log.i("Stopping Recording");
Utilities.isStopping = true;
mediaRecorder.stop();
Log.i("Video Stored@" );
releaseMediaRecorder();
Utilities.isStopping = false;
try {
//camera.reconnect();
//camera.lock();
if(camera == null){
camera = CameraUtils.getCameraInstance();
}
camera.setPreviewDisplay(getHolder());
camera.lock();
camera.startPreview();
}catch(Exception e){
Log.e("Preview display on setpreview after release media recotrdr",e);
}
Utilities.logSensorValues = false;
isRecording = false;
}
}
}
传感器线程:
package priyaman.com.glassdatavisualizer.controllers;
import android.content.Context;
/**
* Created by priya_000 on 5/22/2015.
*/
public class SensorThread extends Thread {
SensorController sensorController;
Context context = null;
DrawViewController drawView = null;
public SensorThread(Context context, DrawViewController drawView){
this.context = context;
this.drawView = drawView;
}
public void run(){
sensorController = new SensorController(context, drawView);
}
}
package priyaman.com.glassdatavisualizer.controllers;
import android.content.Context;
import android.content.ContextWrapper;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Environment;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import priyaman.com.glassdatavisualizer.beans.SensorValueStruct;
import priyaman.com.glassdatavisualizer.utilities.CameraUtils;
import priyaman.com.glassdatavisualizer.utilities.Log;
import priyaman.com.glassdatavisualizer.utilities.Utilities;
/**
* Created by priya_000 on 5/21/2015.
*/
public class SensorController implements SensorEventListener {
private Context context;
private DrawViewController drawView;
// Sensor manager
private SensorManager mSensorManager = null;
// Motion sensors
private Sensor mSensorAccelerometer = null;
private Sensor mSensorGravity = null;
private Sensor mSensorLinearAcceleration = null;
private Sensor mSensorGyroscope = null;
private Sensor mSensorRotationVector = null;
String mediaStorageDir = null;
private void initializeSensorManager()
{
mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
mSensorAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorGravity = mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
mSensorLinearAcceleration = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
mSensorGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
mSensorRotationVector = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
}
public SensorController(Context context, DrawViewController drawView){
Log.d("onServiceStart() called.");
this.context = context;
this.drawView = drawView;
initializeSensorManager();
mSensorManager.registerListener(this, mSensorAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
mSensorManager.registerListener(this, mSensorGravity, SensorManager.SENSOR_DELAY_NORMAL);
mSensorManager.registerListener(this, mSensorLinearAcceleration, SensorManager.SENSOR_DELAY_NORMAL);
mSensorManager.registerListener(this, mSensorGyroscope, SensorManager.SENSOR_DELAY_NORMAL);
mSensorManager.registerListener(this, mSensorRotationVector, SensorManager.SENSOR_DELAY_NORMAL);
mediaStorageDir = CameraUtils.getOutputMediaFile(3).toString();
}
@Override
public void onSensorChanged(SensorEvent event) {
Log.d("onSensorChanged() called.");
processMotionSensorData(event);
if(Utilities.logSensorValues){
StringBuffer strBuf = new StringBuffer();
if(Utilities.lastSensorValuesAccelerometer != null) {
strBuf.append("Accelerometer:\n" + Utilities.lastSensorValuesAccelerometer.toString() + "\n");
}
if(Utilities.lastSensorValuesGravity != null) {
strBuf.append("Gravity:\n" + Utilities.lastSensorValuesGravity.toString() + "\n");
}
if(Utilities.lastSensorValuesLinearAcceleration != null) {
strBuf.append("Linear Acceleration:\n" + Utilities.lastSensorValuesLinearAcceleration.toString() + "\n");
}
if(Utilities.lastSensorValuesGyroscope != null) {
strBuf.append("Gyroscope:\n" + Utilities.lastSensorValuesGyroscope.toString() + "\n");
}
if(Utilities.lastSensorValuesRotationVector != null) {
strBuf.append("Rotation Vector:\n" + Utilities.lastSensorValuesRotationVector.toString() + "\n");
}
if(Utilities.lastSensorValuesRotationVector != null) {
strBuf.append("Timestamp:\n" + Utilities.lastSensorValuesRotationVector.getTimestamp() + "\n");
}
writeToFile(strBuf.toString());
}
if(!Utilities.isStopping)
drawView.invalidate();
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
Log.d("onAccuracyChanged() called.");
}
private void processMotionSensorData(SensorEvent event)
{
long now = System.currentTimeMillis();
Sensor sensor = event.sensor;
int type = sensor.getType();
long timestamp = event.timestamp;
float[] values = event.values;
int accuracy = event.accuracy;
SensorValueStruct data = new SensorValueStruct(type, timestamp, values, accuracy);
switch(type) {
case Sensor.TYPE_ACCELEROMETER:
Utilities.lastSensorValuesAccelerometer = data;
break;
case Sensor.TYPE_GRAVITY:
Utilities.lastSensorValuesGravity = data;
break;
case Sensor.TYPE_LINEAR_ACCELERATION:
Utilities.lastSensorValuesLinearAcceleration = data;
break;
case Sensor.TYPE_GYROSCOPE:
Utilities.lastSensorValuesGyroscope = data;
break;
case Sensor.TYPE_ROTATION_VECTOR:
Utilities.lastSensorValuesRotationVector = data;
break;
default:
Log.w("Unknown type: " + type);
}
}
private void writeToFile(String data) {
try {
//OutputStreamWriter outputStreamWriter = new FileOutputStream(new File(mediaStorageDir),true);//new OutputStreamWriter(context.openFileOutput(mediaStorageDir, Context.MODE_PRIVATE));
FileOutputStream outputStreamWriter = new FileOutputStream(new File(mediaStorageDir),true);//new OutputStreamWriter(context.openFileOutput(mediaStorageDir, Context.MODE_PRIVATE));
outputStreamWriter.write(data.getBytes());
outputStreamWriter.close();
}
catch (IOException e) {
Log.e("Exception" + "File write failed: " + e.toString());
}
}
}