package com.basic.security.utils; import android.annotation.SuppressLint; import android.media.MediaCodec; import android.media.MediaCodecInfo; import android.media.MediaFormat; import android.os.Environment; import com.basic.security.base.BaseApplication; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; public class AvcEncoder { private final static String TAG = "MeidaCodec"; private static String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/test1.h264"; public byte[] configbyte; public boolean isRuning = false; int m_width; int m_height; int m_framerate; byte[] m_info = null; FileOutputStream outStream; ByteBuffer[] inputBuffers; ByteBuffer[] outputBuffers; int count = 0; private int TIMEOUT_USEC = 12000; private MediaCodec mediaCodec; private BufferedOutputStream outputStream; public AvcEncoder() { this(640, 480, 30, 8500 * 1000); } @SuppressLint("NewApi") public AvcEncoder(int width, int height, int framerate, int bitrate) { m_width = width; m_height = height; m_framerate = framerate; MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height); mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar); mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, width * height * 5); mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30); mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); try { mediaCodec = MediaCodec.createEncoderByType("video/avc"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); mediaCodec.start(); createfile(); } private void createfile() { File file = new File(path); if (file.exists()) { file.delete(); } try { outputStream = new BufferedOutputStream(new FileOutputStream(file)); } catch (Exception e) { e.printStackTrace(); } } @SuppressLint("NewApi") private void StopEncoder() { try { mediaCodec.stop(); mediaCodec.release(); } catch (Exception e) { e.printStackTrace(); } } public void StopThread() { isRuning = false; try { StopEncoder(); outputStream.flush(); outputStream.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void StartEncoderThread() { BaseApplication.getApplication().executorService.execute(() -> { isRuning = true; byte[] input = null; long pts = 0; long generateIndex = 0; while (isRuning) { if (Preview.YUVQueue.size() > 0) { input = Preview.YUVQueue.poll(); byte[] yuv420sp = new byte[m_width * m_height * 3 / 2]; NV21ToNV12(input, yuv420sp, m_width, m_height); input = yuv420sp; } if (input != null) { try { long startMs = System.currentTimeMillis(); ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers(); ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers(); int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1); if (inputBufferIndex >= 0) { pts = computePresentationTime(generateIndex); ByteBuffer inputBuffer = inputBuffers[inputBufferIndex]; inputBuffer.clear(); inputBuffer.put(input); mediaCodec.queueInputBuffer(inputBufferIndex, 0, input.length, pts, 0); generateIndex += 1; } MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC); while (outputBufferIndex >= 0) { //Log.i("AvcEncoder", "Get H264 Buffer Success! flag = "+bufferInfo.flags+",pts = "+bufferInfo.presentationTimeUs+""); ByteBuffer outputBuffer = outputBuffers[outputBufferIndex]; byte[] outData = new byte[bufferInfo.size]; outputBuffer.get(outData); if (bufferInfo.flags == 2) { configbyte = new byte[bufferInfo.size]; configbyte = outData; } else if (bufferInfo.flags == 1) { byte[] keyframe = new byte[bufferInfo.size + configbyte.length]; System.arraycopy(configbyte, 0, keyframe, 0, configbyte.length); System.arraycopy(outData, 0, keyframe, configbyte.length, outData.length); // outputStream.write(keyframe, 0, keyframe.length); } else { // outputStream.write(outData, 0, outData.length); } mediaCodec.releaseOutputBuffer(outputBufferIndex, false); outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC); } } catch (Throwable t) { t.printStackTrace(); } } else { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }); } private void NV21ToNV12(byte[] nv21, byte[] nv12, int width, int height) { if (nv21 == null || nv12 == null) return; int framesize = width * height; int i = 0, j = 0; System.arraycopy(nv21, 0, nv12, 0, framesize); for (i = 0; i < framesize; i++) { nv12[i] = nv21[i]; } for (j = 0; j < framesize / 2; j += 2) { nv12[framesize + j - 1] = nv21[j + framesize]; } for (j = 0; j < framesize / 2; j += 2) { nv12[framesize + j] = nv21[j + framesize - 1]; } } /** * Generates the presentation time for frame N, in microseconds. */ private long computePresentationTime(long frameIndex) { return 132 + frameIndex * 1000000 / m_framerate; } }