27

Я использую образец FaceTracker из API видения Android. Тем не менее, я испытываю трудности с записью видео, пока накладываются на них надписи.Медиа-рекордер с API Google Vision

Один из способов - сохранить растровые изображения в качестве изображений и обработать их с помощью FFmpeg или Xuggler, чтобы объединить их в качестве видео, но мне интересно, есть ли лучшее решение этой проблемы, если мы можем записывать видео во время выполнения, когда предварительный просмотр проецируется ,

Update 1: Я обновил following класс с медиа-рекордер, но запись все еще не работает. Он бросает следующее сообщение об ошибке, когда я называю triggerRecording функции():

MediaRecorder: начать называется в нерабочем состоянии: 4

и у меня есть разрешение внешнего хранения в файле манифеста.

Обновление 2:

Я установил выше проблемы в коде и перенес setupMediaRecorder() в onSurfaceCreated обратного вызова. Однако, когда я прекращаю запись, это исключает исключение времени выполнения. Согласно documentation, если нет видео/аудио данных, будет выбрано исключение времени выполнения.

Итак, что мне здесь не хватает?

public class CameraSourcePreview extends ViewGroup { 
    private static final String TAG = "CameraSourcePreview"; 

    private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); 

    static { 
     ORIENTATIONS.append(Surface.ROTATION_0, 90); 
     ORIENTATIONS.append(Surface.ROTATION_90, 0); 
     ORIENTATIONS.append(Surface.ROTATION_180, 270); 
     ORIENTATIONS.append(Surface.ROTATION_270, 180); 
    } 

    private MediaRecorder mMediaRecorder; 
    /** 
    * Whether the app is recording video now 
    */ 
    private boolean mIsRecordingVideo; 

    private Context mContext; 
    private SurfaceView mSurfaceView; 
    private boolean mStartRequested; 
    private boolean mSurfaceAvailable; 
    private CameraSource mCameraSource; 

    private GraphicOverlay mOverlay; 

    public CameraSourcePreview(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     mContext = context; 
     mStartRequested = false; 
     mSurfaceAvailable = false; 

     mSurfaceView = new SurfaceView(context); 

     mSurfaceView.getHolder().addCallback(new SurfaceCallback()); 

     addView(mSurfaceView); 

     mMediaRecorder = new MediaRecorder(); 
    } 

    private void setUpMediaRecorder() throws IOException { 
     mMediaRecorder.setPreviewDisplay(mSurfaceView.getHolder().getSurface()); 
     mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 
     mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); 
     mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); 

     mMediaRecorder.setOutputFile(Environment.getExternalStorageDirectory() + File.separator + Environment.DIRECTORY_DCIM + File.separator + System.currentTimeMillis() + ".mp4"); 
     mMediaRecorder.setVideoEncodingBitRate(10000000); 
     mMediaRecorder.setVideoFrameRate(30); 
     mMediaRecorder.setVideoSize(480, 640); 
     mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); 
     mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); 
     //int rotation = mContext.getWindowManager().getDefaultDisplay().getRotation(); 
     //int orientation = ORIENTATIONS.get(rotation); 
     mMediaRecorder.setOrientationHint(ORIENTATIONS.get(0)); 
     mMediaRecorder.prepare(); 

     mMediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() { 
      @Override 
      public void onError(MediaRecorder mr, int what, int extra) { 
       Timber.d(mr.toString() + " : what[" + what + "]" + " Extras[" + extra + "]"); 
      } 
     }); 
    } 

    public void start(CameraSource cameraSource) throws IOException { 
     if (cameraSource == null) { 
      stop(); 
     } 

     mCameraSource = cameraSource; 

     if (mCameraSource != null) { 
      mStartRequested = true; 
      startIfReady(); 
     } 
    } 

    public void start(CameraSource cameraSource, GraphicOverlay overlay) throws IOException { 
     mOverlay = overlay; 
     start(cameraSource); 
    } 

    public void stop() { 
     if (mCameraSource != null) { 
      mCameraSource.stop(); 
     } 
    } 

    public void release() { 
     if (mCameraSource != null) { 
      mCameraSource.release(); 
      mCameraSource = null; 
     } 
    } 

    private void startIfReady() throws IOException { 
     if (mStartRequested && mSurfaceAvailable) { 
      mCameraSource.start(mSurfaceView.getHolder()); 
      if (mOverlay != null) { 
       Size size = mCameraSource.getPreviewSize(); 
       int min = Math.min(size.getWidth(), size.getHeight()); 
       int max = Math.max(size.getWidth(), size.getHeight()); 
       if (isPortraitMode()) { 
        // Swap width and height sizes when in portrait, since it will be rotated by 
        // 90 degrees 
        mOverlay.setCameraInfo(min, max, mCameraSource.getCameraFacing()); 
       } else { 
        mOverlay.setCameraInfo(max, min, mCameraSource.getCameraFacing()); 
       } 
       mOverlay.clear(); 
      } 

      mStartRequested = false; 
     } 
    } 

    private class SurfaceCallback implements SurfaceHolder.Callback { 
     @Override 
     public void surfaceCreated(SurfaceHolder surface) { 
      mSurfaceAvailable = true; 
      surface.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 

      // setup the media recorder 
      try { 
       setUpMediaRecorder(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 

      try { 
       startIfReady(); 
      } catch (IOException e) { 
       Timber.e(TAG, "Could not start camera source.", e); 
      } 
     } 

     @Override 
     public void surfaceDestroyed(SurfaceHolder surface) { 
      mSurfaceAvailable = false; 
     } 

     @Override 
     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 
     } 
    } 

    @Override 
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 
     int width = 320; 
     int height = 240; 
     if (mCameraSource != null) { 
      Size size = mCameraSource.getPreviewSize(); 
      if (size != null) { 
       width = size.getWidth(); 
       height = size.getHeight(); 
      } 
     } 

     // Swap width and height sizes when in portrait, since it will be rotated 90 degrees 
     if (isPortraitMode()) { 
      int tmp = width; 
      width = height; 
      height = tmp; 
     } 

     final int layoutWidth = right - left; 
     final int layoutHeight = bottom - top; 

     // Computes height and width for potentially doing fit width. 
     int childWidth = layoutWidth; 
     int childHeight = (int) (((float) layoutWidth/(float) width) * height); 

     // If height is too tall using fit width, does fit height instead. 
     if (childHeight > layoutHeight) { 
      childHeight = layoutHeight; 
      childWidth = (int) (((float) layoutHeight/(float) height) * width); 
     } 

     for (int i = 0; i < getChildCount(); ++i) { 
      getChildAt(i).layout(0, 0, childWidth, childHeight); 
     } 

     try { 
      startIfReady(); 
     } catch (IOException e) { 
      Timber.e(TAG, "Could not start camera source.", e); 
     } 
    } 

    private boolean isPortraitMode() { 
     int orientation = mContext.getResources().getConfiguration().orientation; 
     if (orientation == Configuration.ORIENTATION_LANDSCAPE) { 
      return false; 
     } 
     if (orientation == Configuration.ORIENTATION_PORTRAIT) { 
      return true; 
     } 

     Timber.d(TAG, "isPortraitMode returning false by default"); 
     return false; 
    } 

    private void startRecordingVideo() { 
     try { 
      // Start recording 
      mMediaRecorder.start(); 
      mIsRecordingVideo = true; 
     } catch (IllegalStateException e) { 
      e.printStackTrace(); 
     } 
    } 

    private void stopRecordingVideo() { 
     // UI 
     mIsRecordingVideo = false; 
     // Stop recording 
     mMediaRecorder.stop(); 
     mMediaRecorder.reset(); 
    } 

    public void triggerRecording() { 
     if (mIsRecordingVideo) { 
      stopRecordingVideo(); 
      Timber.d("Recording stopped"); 
     } else { 
      startRecordingVideo(); 
      Timber.d("Recording starting"); 
     } 
    } 
} 
+1

Я столкнулся с той же проблемой –

+0

, так вы нашли решение для этого? – Reshma

+0

Из-за нескольких других причин я изменил свой подход и вместо этого использовал OpenCV с GLSurfaceView. Оформить заказ на мой другой вопрос: http://stackoverflow.com/q/33368655/1053097 – muneikh

ответ

0

Решение 1: Из Android Lollipop, MediaProjection API был введен, который в сочетании с MediaRecorder могут быть использованы для сохранения SurfaceView в видеофайл. This example shows how to output a SurfaceView to a video file.

Решение 2: В качестве альтернативы, вы можете использовать один из классов аккуратных кодера, предусмотренных в Grafika repository. Обратите внимание, что для этого потребуется выгрузить приложение FaceTracker, чтобы он использовал OpenGL для выполнения всего рендеринга. Это потому, что образцы Grafika используют конвейер OpenGL для быстрого чтения и записи данных текстуры.

Существует минимальный пример, который обеспечивает то, что вы хотите, используя CircularEncoder в классе ContinuousCaptureActivity. Это дает пример Frame Blitting, одновременно отображая данные буфера кадра на экран и выводя на видео.

Главное изменение заключается в использовании Grafika WindowSurface вместо SurfaceView для приложения FaceTracker, это настраивает контекст EGL, позволяющий сохранять данные буфера кадра в файл через Encoder. Как только вы можете отобразить все на WindowSurface, тривиально настроить запись так же, как класс ContinuousCaptureActivity.

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

  • Нет связанных вопросов^_^