以下为代码
注意:Android硬编码对手机平台有要求,不同平台支持的视频质量以及是否支持硬编码都不相同。
需要关注inputBufferIndex值 以及outputBufferIndex 是否正常。

import java.nio.ByteBuffer;import java.util.Arrays;import android.annotation.SuppressLint;import android.media.MediaCodec;import android.media.MediaCodecInfo;import android.media.MediaCodecList;import android.media.MediaFormat;import android.util.Log;public class AVCEncoder {    private MediaCodec mediaCodec;    int m_width;    int m_height;    byte[] m_info = null;    private byte[] yuv420 = null;    int m_SupportColorFormat = -1;    @SuppressLint("NewApi")    public AVCEncoder(int width, int height, int framerate, int bitrate, int iFrameInterval) {        m_width = width;        m_height = height;        yuv420 = new byte[width * height * 3 / 2];        m_SupportColorFormat = getSupportColorFormat();        if (m_SupportColorFormat != -1) {            mediaCodec = MediaCodec.createEncoderByType("video/avc");            MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height);            mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);            mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, framerate);            mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, m_SupportColorFormat);            mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); // 关键帧间隔时间//            mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);            mediaCodec.start();        } else {            Log.e("AvcEncoder", "mediacodec doesn't work");            // 硬编码不成功        }    }    @SuppressLint("NewApi")    private int getSupportColorFormat() {        int numCodecs = MediaCodecList.getCodecCount();        MediaCodecInfo codecInfo = null;        for (int i = 0; i < numCodecs && codecInfo == null; i++) {            MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);            if (!info.isEncoder()) {                continue;            }            String[] types = info.getSupportedTypes();            boolean found = false;            for (int j = 0; j < types.length && !found; j++) {                if (types[j].equals("video/avc")) {                    System.out.println("found");                    found = true;                }            }            if (!found)                continue;            codecInfo = info;        }        Log.e("AvcEncoder", "Found " + codecInfo.getName() + " supporting " + "video/avc");        // Find a color profile that the codec supports        MediaCodecInfo.CodecCapabilities capabilities = codecInfo.getCapabilitiesForType("video/avc");        Log.e("AvcEncoder",                "length-" + capabilities.colorFormats.length + "==" + Arrays.toString(capabilities.colorFormats));        for (int i = 0; i < capabilities.colorFormats.length; i++) {            switch (capabilities.colorFormats[i]) {            case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar:            case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar:            case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar:            case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar:            case MediaCodecInfo.CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar:            case MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar:                Log.e("AvcEncoder", "supported color format::" + capabilities.colorFormats[i]);                return capabilities.colorFormats[i];            default:                Log.e("AvcEncoder", "unsupported color format " + capabilities.colorFormats[i]);                break;            }        }        return -1;    }    @SuppressLint("NewApi")    public void close() {        try {            mediaCodec.stop();            mediaCodec.release();        } catch (Exception e) {            e.printStackTrace();        }    }    class EncodeResult {        private static final int FRAME_IVALID = -1;        private static final int FRAME_IFRAME = 1;        private static final int FRAME_PFRAME = 2;        private static final int FRAME_ENCODE_LEN_INVALID = -1;        private int frameFlag;        private int encodeLen;        private int frameIndex;        public EncodeResult() {            super();            // TODO Auto-generated constructor stub        }        public EncodeResult(int frameFlag, int encodeLen) {            super();            this.frameFlag = frameFlag;            this.encodeLen = encodeLen;        }        public int getFrameIndex() {            return frameIndex;        }        public void setFrameIndex(int frameIndex) {            this.frameIndex = frameIndex;        }        public int getFrameFlag() {            return frameFlag;        }        public void setFrameFlag(int frameFlag) {            this.frameFlag = frameFlag;        }        public int getEncodeLen() {            return encodeLen;        }        public void setEncodeLen(int encodeLen) {            this.encodeLen = encodeLen;        }    }    private int frameIndex = 0;    @SuppressLint("NewApi")    public EncodeResult offerEncoder(byte[] input, byte[] output) {        EncodeResult result = new EncodeResult();        int pos = 0;        switch (m_SupportColorFormat) {        case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar:            YV12toYUV420Planar(input, yuv420, m_width, m_height);            break;        case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar:            // todo            break;        case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar:            YV12toYUV420PackedSemiPlanar(input, yuv420, m_width, m_height);            break;        case MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar:            // todo            break;        case MediaCodecInfo.CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar:            // todo            break;        case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar:            YV12toYUV420SemiPlanar(input, yuv420, m_width, m_height);            break;        default:            break;        }        try {            ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();            ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();            int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);            //Log.i("lee", "inputBufferIndex:" + inputBufferIndex);            if (inputBufferIndex >= 0) {                ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];                inputBuffer.clear();                inputBuffer.put(yuv420);                mediaCodec.queueInputBuffer(inputBufferIndex, 0, yuv420.length, 0, 0);            }            MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();            int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);            //Log.i("lee", "outputBufferIndex:" + outputBufferIndex);            while (outputBufferIndex >= 0) {                ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];                byte[] outData = new byte[bufferInfo.size];                outputBuffer.get(outData);                if (m_info != null) {                    System.arraycopy(outData, 0, output, pos, outData.length);                    pos += outData.length;                } else {                    // 保存pps sps 只有开始时 第一个帧里有, 保存起来后面用                    ByteBuffer spsPpsBuffer = ByteBuffer.wrap(outData);                    if (spsPpsBuffer.getInt() == 0x00000001) {                        m_info = new byte[outData.length];                        System.arraycopy(outData, 0, m_info, 0, outData.length);                    } else {                        return new EncodeResult(EncodeResult.FRAME_IVALID, EncodeResult.FRAME_ENCODE_LEN_INVALID);                    }                }                mediaCodec.releaseOutputBuffer(outputBufferIndex, false);                outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);            }            // key frame 编码器生成关键帧时只有 00 00 00 01 65            // 没有pps            // sps, 要加上            if (output[4] == 0x65) {                System.arraycopy(output, 0, yuv420, 0, pos);                System.arraycopy(m_info, 0, output, 0, m_info.length);                System.arraycopy(yuv420, 0, output, m_info.length, pos);                pos += m_info.length;                frameIndex = 0;                result.setFrameFlag(EncodeResult.FRAME_IFRAME);            } else {                frameIndex++;                result.setFrameFlag(EncodeResult.FRAME_PFRAME);            }        } catch (Throwable t) {            t.printStackTrace();        }        result.setEncodeLen(pos);        result.setFrameIndex(frameIndex);        return result;    }    public static void YV12toYUV420PackedSemiPlanar(final byte[] input, final byte[] output, final int width,            final int height) {        /*         * COLOR_TI_FormatYUV420PackedSemiPlanar is NV12 We convert by putting         * the corresponding U and V bytes together (interleaved).         */        final int frameSize = width * height;        final int qFrameSize = frameSize / 4;        System.arraycopy(input, 0, output, 0, frameSize); // Y        for (int i = 0; i < qFrameSize; i++) {            output[frameSize + i * 2] = input[frameSize + i + qFrameSize]; // Cb                                                                            // (U)            output[frameSize + i * 2 + 1] = input[frameSize + i]; // Cr (V)        }    }    public static void YV12toYUV420Planar(byte[] input, byte[] output, int width, int height) {        /*         * COLOR_FormatYUV420Planar is I420 which is like YV12, but with U and V         * reversed. So we just have to reverse U and V.         */        final int frameSize = width * height;        final int qFrameSize = frameSize / 4;        System.arraycopy(input, 0, output, 0, frameSize); // Y        System.arraycopy(input, frameSize, output, frameSize + qFrameSize, qFrameSize); // Cr                                                                                        // (V)        System.arraycopy(input, frameSize + qFrameSize, output, frameSize, qFrameSize); // Cb                                                                                        // (U)    }    public static void YV12toYUV420SemiPlanar(final byte[] input, final byte[] output, final int width,            final int height) {        final int frameSize = width * height;        final int qFrameSize = frameSize / 4;        int padding = 1024;        if ((width == 640 && height == 480) || width == 1280 && height == 720)            padding = 0;        System.arraycopy(input, 0, output, 0, frameSize);        for (int i = 0; i < (qFrameSize); i++) {            output[frameSize + i * 2 + padding] = (input[frameSize + qFrameSize + i]);            output[frameSize + i * 2 + 1 + padding] = (input[frameSize + i]);        }    }}

更多相关文章

  1. [Android][MediaRecorder] Android(安卓)MediaRecorder框架简洁
  2. MTK平台 Sensor Hub配置(以stk3x3x光感为例)(Android(安卓)9.0)
  3. android fragment用get/setArguments()传值
  4. Facebook发布React Native for Android
  5. Android平台开发-WIFI function porting-WIFI功能移植
  6. Android(安卓)MD5加密算法
  7. Android(安卓)SDK Manager下载,解决方案
  8. Android剪切板设置和读取字符串String 关键代码
  9. 深入浅出 - Android系统移植与平台开发(十三) - Sensor HAL框架分

随机推荐

  1. mac下安装mysql忘记密码的修改方法
  2. 通过案例分析MySQL中令人头疼的Aborted告
  3. 利用pt-heartbeat监控MySQL的复制延迟详
  4. 解决MySQL中IN子查询会导致无法使用索引
  5. CentOS6.7 mysql5.6.33修改数据文件位置
  6. 简述MySQL与Oracle的区别
  7. 关于Win10下MySQL5.7.17免安装版基本配置
  8. Win7 64位 mysql 5.7下载安装常见问题小
  9. 详解MySQL主从复制读写分离搭建
  10. MySQL 去除重复数据实例详解