2011-06-17 13 views
7

Estoy usando el desarrollo de Android (SDK 2.2) y me gustaría hacer una grabación de video con mediaRecorder y, al mismo tiempo, hacer algún proceso en cada marco de vista previa.Android preview processing while video recording

Me grabar vídeo con MediaRecorder en un proyecto, en un otro uso el onPreviewFrame(byte[] data, Camera camera) (de PreviewCallback) para el procesamiento de imágenes de vista previa.

He intentado crear una cámara y usarla con mediaRecorder (función setCamera) pero no funciona.

¿Es posible hacer ambas cosas al mismo tiempo?

¿Realmente no entiendo cómo relacionar dos cosas?

Mi código:

package ch.fraise; 

import java.io.IOException; 
import android.app.Activity; 
import android.hardware.Camera; 
import android.hardware.Camera.PreviewCallback; 
import android.media.MediaRecorder; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.Menu; 
import android.view.MenuInflater; 
import android.view.MenuItem; 
import android.view.SurfaceHolder; 
import android.view.SurfaceView; 

public class CameraActivity extends Activity implements SurfaceHolder.Callback, 
    Camera.AutoFocusCallback { 

private SurfaceView preview; 
private SurfaceHolder previewHolder; 

private MediaRecorder mRecorder; 
private Camera mCamera; 
private boolean mPreviewRunning = false; 
private boolean mCaptureFrame = false; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    Log.e("", "Begin onCreate"); 
    setContentView(R.layout.main); 

    preview = (SurfaceView) findViewById(R.id.surfaceView1); 
    previewHolder = preview.getHolder(); 
    previewHolder.addCallback(this); 
    previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 

    mRecorder = new MediaRecorder(); 
} 

@Override 
public void onResume() { 
    super.onResume(); 
} 

@Override 
public void onPause() { 
    super.onPause(); 
} 

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    MenuInflater inflater = getMenuInflater(); 
    inflater.inflate(R.menu.capture_menu, menu); 
    return true; 
} 

public void startRecording() { 
    Log.e("", "Begin StartRecording"); 
    mCaptureFrame = true; 
    mRecorder.start(); 
} 

public void stopRecording() { 
    Log.e("", "Begin StopChange"); 
    mRecorder.stop(); 
} 

@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
    // Handle item selection 
    switch (item.getItemId()) { 
    case R.id.startRecording: 
     startRecording(); 
     return true; 
    case R.id.stopRecording: 
     stopRecording(); 
     return true; 
    default: 
     return super.onOptionsItemSelected(item); 
    } 
} 

@Override 
public void surfaceCreated(SurfaceHolder holder) { 
    Log.e("", "Begin surfaceDestroy"); 
    mCamera = Camera.open(); 
} 

@Override 
public void surfaceDestroyed(SurfaceHolder holder) { 
    mCamera.stopPreview(); 
    mPreviewRunning = false; 
    mCamera.release(); 

    mRecorder.reset(); 
    mRecorder.release(); 
} 

@Override 
public void onAutoFocus(boolean success, Camera camera) { 
    // TODO Auto-generated method stub 

} 

/* 
* PreviewCallback() 
* 
* this callback captures the preview at every frame and puts it in a byte 
* buffer. we will evaluate if this is a frame that we want to process, and 
* if so, we will send it to an asynchronous thread that will process it to 
* an ARGB Bitmap and POST it to the server 
*/ 
PreviewCallback previewCallback = new PreviewCallback() { 
    public void onPreviewFrame(byte[] data, Camera camera) { 
     Log.e("", "onPreviewFrame pass"); 
     if (mCaptureFrame) { 
      mCaptureFrame = false; 
      // new FrameHandler().execute(data); 
     } 
    } 
}; 

@Override 
public void surfaceChanged(SurfaceHolder holder, int format, int width, 
     int height) { 
    Log.e("", "Begin SurfaceChange"); 

    mRecorder.reset(); 
    mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 
    mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); 
    mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP); 
    mRecorder.setOutputFile("/sdcard/videotest2.mp4"); 
    mRecorder.setVideoFrameRate(30); 

    mRecorder.setPreviewDisplay(previewHolder.getSurface()); 
    try { 
     mRecorder.prepare(); 
    } catch (IllegalStateException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    if (mPreviewRunning) 
     mCamera.stopPreview(); 

    Camera.Parameters p = mCamera.getParameters(); 
    // p.setPreviewSize(width, height); 
    mCamera.setParameters(p); 

    try { 
     mCamera.setPreviewDisplay(holder); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    mCamera.setPreviewCallback(previewCallback); 

    mCamera.startPreview(); 
    mPreviewRunning = true; 

} 

} 

y los permisos en el archivo XML:

<uses-permission android:name="android.permission.CAMERA" /> 
<uses-permission android:name="android.permission.RECORD_AUDIO" /> 
<uses-permission android:name="android.permission.RECORD_VIDEO" /> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
+0

¿Cuál es tu pregunta? – YXD

+0

he agregado mi código pero tengo el siguiente error W/System.err (5476): java.io.IOException: prepare failed. la aplicación se ejecuta después de este primer error, hasta que empiece la grabación de video. Entonces tengo una java.lang.IllegalStateException E/AndroidRuntime (5476): en android.media.MediaRecorder.start (método nativo) –

Respuesta

0

Usted acaba de añadir etiquetas a su archivo de manifiesto .Así se work.Sample código que se muestra a continuación.

por ejemplo: -

</application> 
    <uses-permission android:name="android.permission.CAMERA" /> 
<uses-permission android:name="android.permission.RECORD_AUDIO" /> 
<uses-permission android:name="android.permission.RECORD_VIDEO" /> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
    ***<uses-feature android:name="android.hardware.camera" />*** 
</manifest> 
+0

Hola nikhilkilivayil! ¡Gracias por tu ayuda! Lamentablemente, he agregado la línea pero parece que tampoco funciona. ¡He visto cuando la grabación comienza, el onFramePreview deja de llamarse! ¿Tal vez puedan correr juntos? –

+0

Tengo el mismo problema. Si tiene la respuesta, infórmeme ... – nikhilkilivayil

+0

Tengo este problema también. ¿Puede ser que podamos intentar decodificar el video mientras tanto para obtener la imagen en bruto en tiempo real? –

4

no puede acceder a la secuencia de vídeo durante la grabación, onPreviewFrame no se llamará una vez que comience la grabación. Curiosamente, no parece onPreviewFrame a ser llamado después de grabar, ya sea ...

+1

Eso está mal. Simplemente necesita comenzar a escuchar nuevamente después de la grabación. –

0

si está utilizando OS 2.2 o superior y luego utilizar este método a su prepárese falló y será eliminado otra excepción

public boolean startRecording() { 
    try { 
     camera.unlock(); 

     mediaRecorder = new MediaRecorder(); 
     mediaRecorder.setCamera(camera); 
     mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); 
     mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 
     mediaRecorder.setProfile(CamcorderProfile 
       .get(CamcorderProfile.QUALITY_HIGH)); 

     File tempFile = new File(getOutputMediaFile(MEDIA_TYPE_VIDEO) 
       .toString()); 

     mediaRecorder.setOutputFile(tempFile.getPath()); 
     mediaRecorder.setVideoFrameRate(videoFramesPerSecond); 
     mediaRecorder.setVideoSize(surfaceView.getWidth(), 
       surfaceView.getHeight()); 
     mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface()); 
     mediaRecorder.setMaxFileSize(maxFileSizeInBytes); 
     mediaRecorder.prepare(); 
     mediaRecorder.start(); 

     return true; 
    } catch (IllegalStateException e) { 
     Log.e(TAG, e.getMessage()); 
     e.printStackTrace(); 
     return false; 
    } catch (IOException e) { 
     Log.e(TAG, e.getMessage()); 
     e.printStackTrace(); 
     return false; 
    } 
} 
6

Eureka! ¡El truco es unir tu PreviewCallback en el surfaceChanged(...)SurfaceHolder.Callback! ¡Después de hacer esto, continuará obteniendo datos de cuadros de vista previa después de que se esté ejecutando MediaRecorder!

Por ejemplo:

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 
    mCamera.setPreviewCallback(new PreviewCallback() { 
      public void onPreviewFrame(byte[] _data, Camera _camera) { 
       Log.d("onPreviewFrame-surfaceChanged",String.format("Got %d bytes of camera data", _data.length)); 
      } 
     }); 

} 
+1

Lo hago como se muestra arriba, pero aún no puedo obtener datos de cuadros de vista previa después de que se está ejecutando un MediaRecorder. ¿Realmente funciona para ti? – whutdyp

+0

Sí, estaba usando Android 4.2 en ese momento. Asegúrate de adjuntar el SufaceHolder.Devolución de llamada antes de iniciar MediaRecorder. Publica tu fuente y voy a echar un vistazo. – dbro

+0

@dbro, no. Tu truco no funciona. Si llamo al método 'mMediaRecorder.setCamera (mCamera)', entonces debo llamar 'mCamera.unlock()' antes de lo que no permite obtener marcos de vista previa. Si no llamo al método 'mMediaRecorder.setCamera (mCamera)', 'mMediaRecorder.start()' se bloquea con 'IllegalStateException' porque la cámara ya está en uso. ¿Puedes publicar más código (o completo) cómo hiciste tu truco de eureka? –