3

I am doing android video recording using mediacodec + mediamuxer, and now I can record video and generate mp4 file which can be played. The problem is that I find the recorded video will seize for about one second some time. So I launched traceview and I find MediaMuxer.nativeWriteSampleData() cause the problem. Sometimes this function is very fast and returns within several micro-seconds, but sometimes this function is very slow and will consume about one second or so, and the video blocks at that time. I do not know why this function will perform so varying from time to time. The recording target file is located at external SDCard or internal storage, and the problem exist on both media.

Neo

Neo Song
  • 31
  • 4
  • Which device? What version of Android? – fadden Mar 27 '15 at 15:22
  • AllWinner A80, Optimus Board, Android 4.4.2 – Neo Song Mar 28 '15 at 11:21
  • Can anyone give me a hint how to solve this kind of problem? Just a general methodology is also welcome. – Neo Song Mar 30 '15 at 03:15
  • Dear fadden, I find the similar problem reported in this thread: [question link](http://stackoverflow.com/questions/19361770/muxing-camera-preview-h264-encoded-elementary-stream-with-mediamuxer). However i have already put the function `drainEncoder()` in a separate thread, but the problem still exists. My recording video resolution is 1920x1080 with 10Mbps bit rate. – Neo Song Mar 30 '15 at 14:23

1 Answers1

4

This is a problem that occurs mostly on devices with lower writing flash speeds or if you try to write to the SD card. The solution is to copy the encoded data to a temporary ByteBuffer, release the data back to MediaCodec and call writeSampleData asynchronously on a dedicated thread.

So, assuming that you have a thread for draining MediaCodec's ouput and one for feeding MediaMuxer, this is a possible solution:

// this runs on the MediaCodec's draining thread
public void writeSampleData(final MediaCodec mediaCodec, final int trackIndex, final int bufferIndex, final ByteBuffer encodedData, final MediaCodec.BufferInfo bufferInfo) {
    final ByteBuffer data = ByteBuffer.allocateDirect(bufferInfo.size); // allocate a temp ByteBuffer
    data.put(encodedData);  // copy the data over
    mediaCodec.releaseOutputBuffer(bufferIndex, false); // return the packet to MediaCodec

    mWriterHandler.post(new Runnable() {
        // this runs on the Muxer's writing thread
        @Override
        public void run() {
            mMuxer.writeSampleData(trackIndex, data, bufferInfo); // feed the packet to MediaMuxer
        });
}

The problem with this approach is that we allocate a new ByteBuffer for every incoming packet. It would be better if we could re-use a big circular buffer to enqueue and deque the new data. I have written a post about this matter and also propose a solution which is rather lengthy to explain here. You can read it here.

Petrakeas
  • 1,521
  • 15
  • 28