2011-06-17 3 views
7

Я использую Android-разработку (SDK 2.2), и я хотел бы сделать видеозапись с mediaRecorder и, в то же время, сделать некоторый процесс на каждом кадре предварительного просмотра.Обработка предварительного просмотра Android во время видеозаписи

я запись видео с MediaRecorder в проекте, в другом я использую onPreviewFrame(byte[] data, Camera camera) (от PreviewCallback) для обработки предварительного просмотра изображений.

Я попытался создать камеру и использовать ее с функцией mediaRecorder (setCamera), но она не работает.

Возможно ли это сделать одновременно?

На самом деле я не понимаю, как связать две вещи?

Мой код:

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; 

} 

} 

и разрешения в файле 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

Что ваш вопрос? – YXD

+0

Я добавил свой код, но у меня есть следующая ошибка W/System.err (5476): java.io.IOException: подготовка не удалась. приложение запускается после этой первой ошибки, пока я не начну запись видео. Тогда у меня есть java.lang.IllegalStateException E/AndroidRuntime (5476): на android.media.MediaRecorder.start (родной метод) –

ответ

0

Вы просто добавить тег в файл манифеста .Таким образом это будет work.Sample код, приведенный ниже.

например: -

</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

Привет nikhilkilivayil! Спасибо за вашу помощь! К сожалению, я добавил строку , но, похоже, она не работает. Я видел, когда начинается запись, onFramePreview перестает быть вызванным! Может быть, они могут бегать вместе !? –

+0

У меня такая же проблема. Если вы получили ответ, пожалуйста, сообщите мне. – nikhilkilivayil

+0

У меня тоже есть эта проблема. Может быть, мы можем попытаться декодировать видео тем временем, чтобы получить исходное изображение в реальном времени? –

4

вы не можете получить доступ к видео потока во время записи, onPreviewFrame не будет вызвана, как только вы начнете запись. Как ни странно, onPreviewFrame, кажется, не дозвонились после записи либо ...

+1

Это неправильно. Вам просто нужно начать слушать снова после записи. –

0

, если вы используете ОС 2.2 или выше, а затем использовать этот метод, ваш подготовка не удалось, и другое исключение будет удалено

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

Эврика! Хитрость заключается в том, чтобы прикрепить ваш PreviewCallback в surfaceChanged(...)SurfaceHolder.Callback! После этого вы будете продолжать получать данные кадра предварительного просмотра после запуска MediaRecorder!

Например:

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

Я делаю это как выше, но все еще не могу получить данные кадра предварительного просмотра после запуска MediaRecorder! Это действительно работает для вас? – whutdyp

+0

Да, я использовал Android 4.2 в то время. Убедитесь, что вы подключили SufaceHolder.Обратный вызов перед запуском MediaRecorder. Отправьте свой источник, и я посмотрю. – dbro

+0

@dbro, no. Твой трюк не работает. Если я вызываю метод 'mMediaRecorder.setCamera (mCamera)', тогда я должен вызывать 'mCamera.unlock()' до того, что не позволяет получать кадры предварительного просмотра. Если я не вызываю метод 'mMediaRecorder.setCamera (mCamera)', 'mMediaRecorder.start()' вылетает с 'IllegalStateException', потому что камера уже используется. Можете ли вы опубликовать больше (или полный) код, как вы сделали трюк в eureka? –

Смежные вопросы