美文网首页ijkplayer秘籍
Android平台硬件编码总结一

Android平台硬件编码总结一

作者: deep_sadness | 来源:发表于2018-04-27 16:48 被阅读12次

MediaCodec编码的套路

状态

来自官网的状态图


codec_status.png

创建

  • find Support Codec
    通过这种方式可以得到当前设备所有的MedaCodecInfo
public static final String VIDEO_AVC = MIMETYPE_VIDEO_AVC; // H.264 Advanced Video Coding
    public static final String AUDIO_AAC = MIMETYPE_AUDIO_AAC; // H.264 Advanced Audio Coding

    //得到制定的MimeType的Codec
    public static Single<List<MediaCodecInfo>> getAdaptiveEncoderCodec(String mimeType) {
        return Observable
                .fromArray(getMediaCodecInfos())
                .filter(mediaCodecInfo -> {
                    if (mediaCodecInfo.isEncoder()) {
                        try {
                            MediaCodecInfo.CodecCapabilities capabilitiesForType = mediaCodecInfo.getCapabilitiesForType(mimeType);
                            return capabilitiesForType != null;
                        } catch (Exception e) {
                            e.printStackTrace();
                            return false;
                        }
                    }
                    return false;
                })
                .toList()
                ;
    }

    private static MediaCodecInfo[] getMediaCodecInfos() {
        //获取当前可以支持的MediaCodec
        MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
        //得到所有CodecInfos
        return mediaCodecList.getCodecInfos();
    }
  • MediaFormat
    再通过我们自己的配置和选择的MediaCodecInfo进行创建MediaFormat
MediaFormat toFormat() {
        //通过MimeType创建宽和高
        MediaFormat format = MediaFormat.createVideoFormat(mimeType, width, height);
        //设置ColorFormat .因为这里是mediaProjection来的数据,所以是 Color_FomatSurface
        //如果是使用camera,则这里是 COLOR_FormatYUV420SemiPlanar
        format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);

        format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
        format.setInteger(MediaFormat.KEY_FRAME_RATE, framerate);
        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, iframeInterval);
        if (codecProfileLevel != null && codecProfileLevel.profile != 0 && codecProfileLevel.level != 0) {
            format.setInteger(MediaFormat.KEY_PROFILE, codecProfileLevel.profile);
            format.setInteger("level", codecProfileLevel.level);
        }
        // maybe useful
        // format.setInteger(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, 10_000_000);
        return format;
    }
  • 启动MediaCodec
MediaFormat format = createMediaFormat();
Log.d("Encoder", "Create media format: " + format);

String mimeType = format.getString(MediaFormat.KEY_MIME);
final MediaCodec encoder = createEncoder(mimeType);
try {
    //这里是通过异步的方式创建
     encoder.setCallback(this.mCallback == null ? null : mCodecCallback);
    //调用configure方法,让Codec进入configured状态
     encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
    //如果需要codec提供输入的surface,则在configured状态后,创建
     onEncoderConfigured(encoder);
    //开启encoder
     encoder.start();
 } catch (MediaCodec.CodecException e) {
     Log.e("Encoder", "Configure codec failure!\n  with format" + format, e);
     throw e;
}

Input

  • 实例1:从Camera中得到数据


    camera_input.png
  • 实例2:从MediaProjection创建的VirtualDisplay中得到数据


    virtualdisplay_input.png

output

从MediaCodec中得到编码好的数据。例如H264裸流数据进行处理。

  • 同步的方式


    sync_output.png
  • 异步的方式


    async_output.png

相关文章

网友评论

    本文标题:Android平台硬件编码总结一

    本文链接:https://www.haomeiwen.com/subject/pabblftx.html