2016-03-19 18 views
0

このURLを使用してonpreviewframeデータをmp4ビデオにエンコードするコードを書きましたが、この仕事をうまくやるためにスレッドを使用しましたが、正しく動作しないようです。mediacodecがスムーズに動作しない

private void initCodec() { 
    String root = Environment.getExternalStorageDirectory().toString(); 
    File myDir = new File(root + "/Vocalist"); 
    if(!myDir.exists()) { 
     myDir.mkdirs(); 
    } 
    try { 
     File file = new File (myDir, "myVideo.mp4"); 
     if(file.exists()){ 
      file.delete(); 
     } 
     fos = new FileOutputStream(file, false); 
    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    }try { 
     mMediaCodec = MediaCodec.createEncoderByType("video/avc"); 
    } 
    catch (Exception e){ 

    } 
    MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 
      320, 
      240); 
    mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 500000); 
    mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15); 
    mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, 
      MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar); 
    mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5); 
    mMediaCodec.configure(mediaFormat, 
      null, 
      null, 
      MediaCodec.CONFIGURE_FLAG_ENCODE); 
    mMediaCodec.start(); 
    inputBuffers = mMediaCodec.getInputBuffers(); 
    outputBuffers = mMediaCodec.getOutputBuffers(); 

} 

private synchronized void encode(byte[] dataInput) 
{ 
    byte[] data = dataInput; 
    inputBuffers = mMediaCodec.getInputBuffers();// here changes 
    outputBuffers = mMediaCodec.getOutputBuffers(); 

    int inputBufferIndex = mMediaCodec.dequeueInputBuffer(-1); 

    if (inputBufferIndex >= 0) { 
     ByteBuffer inputBuffer = inputBuffers[inputBufferIndex]; 
     inputBuffer.clear(); 
     inputBuffer.put(data); 
     mMediaCodec.queueInputBuffer(inputBufferIndex, 0, data.length, 0, 0); 
    } else { 
     return; 
    } 

    MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); 
    int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 0); 
    Log.i("tag", "outputBufferIndex-->" + outputBufferIndex); 
    do { 
     if (outputBufferIndex >= 0) { 
      ByteBuffer outBuffer = outputBuffers[outputBufferIndex]; 
      System.out.println("buffer info-->" + bufferInfo.offset + "--" 
        + bufferInfo.size + "--" + bufferInfo.flags + "--" 
        + bufferInfo.presentationTimeUs); 
      byte[] outData = new byte[bufferInfo.size]; 
      outBuffer.get(outData); 
      try { 
       if (bufferInfo.offset != 0) { 
        fos.write(outData, bufferInfo.offset, outData.length 
          - bufferInfo.offset); 
       } else { 
        fos.write(outData, 0, outData.length); 
       } 
       fos.flush(); 
       Log.i("camera", "out data -- > " + outData.length); 
       mMediaCodec.releaseOutputBuffer(outputBufferIndex, false); 
       outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 
         0); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { 
      outputBuffers = mMediaCodec.getOutputBuffers(); 
     } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 
      MediaFormat format = mMediaCodec.getOutputFormat(); 
     } 
    } while (outputBufferIndex >= 0); 
} 

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 

     if (mHolder.getSurface() == null) { 
      return; 
     } 

     try { 

      initCodec(); 
      mCamera.setPreviewDisplay(mHolder); 
      mCamera.setPreviewCallback(new Camera.PreviewCallback() { 
       @Override 
       public void onPreviewFrame(final byte[] bytes, Camera camera) { 
        if (recording == true) { 
         if(mThread.isAlive()) 
          encode(bytes); 

        } 
       } 
      }); 






     } catch (Exception e) { 
      Log.d("TAG", "Error starting camera preview: " + e.getMessage()); 
     } 
    } 
} 
    public void newOpenCamera() { 
    if (mThread == null) { 
     mThread = new CameraHandlerThread(); 
    } 

    synchronized (mThread) { 
     mThread.openCamera(); 
    } 
} 

private static void oldOpenCamera() { 
    try { 
     c = Camera.open(1); 
     Camera.Parameters parameters = c.getParameters(); 
     parameters.set("orientation", "portrait"); 
     parameters.setJpegQuality(100); 
     parameters.setPreviewFormat(ImageFormat.NV21); 
     parameters.setPreviewSize(320, 240); 
     c.setParameters(parameters); 
    } 
    catch (RuntimeException e) { 
     Log.e("camera", "failed to open front camera"); 
    } 
} 

public CameraHandlerThread mThread = null; 
public static class CameraHandlerThread extends HandlerThread { 
    Handler mHandler = null; 


    CameraHandlerThread() { 
     super("CameraHandlerThread"); 
     start(); 
     mHandler = new Handler(getLooper()); 
    } 

    synchronized void notifyCameraOpened() { 
     notify(); 

    } 

    public void openCamera() { 
     mHandler.post(new Runnable() { 
      @Override 
      public void run() { 
       oldOpenCamera(); 
       notifyCameraOpened(); 
      } 
     }); 
    } 
} 

私はビデオにonpreviewframeデータを変換するが、第一、第二の映像の後にスムーズに再生できません。私は何をすべきか ?

答えて

1

まず、あなたは、フレームタイミング情報を転送していない:

mMediaCodec.queueInputBuffer(inputBufferIndex, 0, data.length, 0, 0) 

あなたがバッファをデキューするときだからあなたBufferInfo.presentationTimeUsは常にゼロになります。

第2に、MediaMuxerを使用しているようには見えません。つまり、生のH.264ストリームをファイルに書き込むだけです。これは ".mp4"ではありません。タイミング情報はまったく含まれていません。多くのビデオプレーヤーは、平凡なH.264で何をすべきか知りません。

カメラからのフレームタイミングでファイルを.mp4としてラッピングすると、より良い結果が得られます。

あなたのコード構造は、入力の1つのフレームを供給し、常に1つのフレームの出力を得ることができると仮定しているように見えます。入力をフルに保ち、出力が使用可能になると排水します。

bigflakeGrafikaに詳細とサンプルコードがあります。

+0

私はbigflakeのコードを見てきましたが、CameraToMpegTest.javaという名前の例がありますが、どうすればよいのでしょうか?それはとても大きいです。あなたがその例を実行することについて私に教えてくれれば素晴らしいでしょう。 –

関連する問題