Android平台硬件编码总结一

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏增长技术

Android 相机功能模块相关库

Android’s video recording APIs are very difficult to figure out, especially sinc...

1781
来自专栏Vamei实验室

安卓第九夜 狂风

我们经常需要在安卓应用中包含简易的网页显示功能。我将在这一讲中实现网页的显示。 《狂风》,来自小Willem,荷兰画派黄金时代的作品。作为当时海上马车夫的荷兰,...

2077
来自专栏Android干货

项目实战工具类(一):PhoneUtil(手机信息相关)

1905
来自专栏pangguoming

Android 子activity关闭 向父activity传值

使用startActivity方式启动的Activity和它的父Activity无关,当它关闭时也不会提供任何反馈。 可变通的,你可以启动一个Activity作...

3645
来自专栏何俊林

音视频的采集、编码、封包成 mp4 输出

使用 Android Camera API 完成音视频的采集、编码、封包成 mp4 输出 基于android.hardware.Camera,创建一个横屏应用,...

1464
来自专栏潇涧技术专栏

Android Dependency Injection Libraries

本文总结并对比了三种Android依赖注入库:Butter Knife、RoboGuice、Android Annotations的使用

871
来自专栏飞雪无情的博客

Android Intents and Intent Filters(二)

类别在中是通过标记定义的,Category和Action一样,他们的名字都是一个字符串定义,但是我们在代码中可以使用对应的类别常量,在xml文件定义中只能使用定...

1103
来自专栏刘望舒

感受LiveData与ViewModel结合之美

虽说这篇是说LiveData与ViewModel,但是或多或少都有涉及另外一个组件:Lifecycles 。它们连同Room都是在17年谷歌IO大会推出的,当时...

1212
来自专栏酷玩时刻

Android MVP 构架封装

上一篇我们简单实现了一个MVP的构架,下面我们来做一个简单的封装使其使用更简单方便

993
来自专栏项勇

笔记83 | wifi解析使用

WifiManager是管理android WIFI的连接服务,它可以配置WIFI网络连接,管理当前wifi连接,扫描接入点,监视wifi连接状态;

842

扫码关注云+社区