Android平台GB28181设备接入、RTMP推送模块如何实现高效率的视频编码

简介: 我们在做Android平台RTMP推送、轻量级RTSP服务和GB28181设备接入模块的时候,有一个点是逃不掉的:如何高效率的实现视频数据编码?

我们在做Android平台RTMP推送、轻量级RTSP服务和GB28181设备接入模块的时候,有一个点是逃不掉的:如何高效率的实现视频数据编码?


为此,我们设计了软编码、基于MediaCodec的硬编码和MediaCodec native层硬编,尽可能的减少数据拷贝和交互,确保高效率的完成视频编码,目前,编码前数据类型,已经涵盖了YV12/NV21/NV12/I420/RGB24/RGBA32/RGB565等数据类型,无论是自己采集的数据,还是Android摄像头和camera2和屏幕采集的数据,均可实现高效率的编码。


尽管软编码有各种好处,但受限于设备配置,超过720p的,在一些特定设备,软编总是差强人意,所以Android平台,在设备允许的前提下,还是需要精细化的硬编解决方案。


为此,我们设计了以下接口:

     /**
    * Set Video H.264 HW Encoder, if support HW encoder, it will return 0(设置H.264硬编码)
    * 
    * @param kbps: the kbps of different resolution.
    * 
    * @return {0} if successful
    */
   public native int SetSmartPublisherVideoHWEncoder(long handle, int kbps);
  /**
   * Set Video H.265(hevc) hardware encoder, if support H.265(hevc) hardware encoder, it will return 0(设置H.265硬编码)
   *
   * @param kbps: the kbps of different resolution.
   *
   * @return {0} if successful
   */
  public native int SetSmartPublisherVideoHevcHWEncoder(long handle, int kbps);

两个接口,分别对应设置264、265硬编,如果不支持,自动切换到软编。


码率模式选择:

  /*
  * 设置视频硬编码码率控制模式
  * @param hw_bitrate_mode: -1表示使用默认值, 不设置也会使用默认值, 0:CQ, 1:VBR, 2:CBR, 3:CBR_FD, 请参考:android.media.MediaCodecInfo.EncoderCapabilities
  * 注意硬编码和手机硬件有关,多数手机只支持部分码率模式, 另外硬编码设备差异很大,不同设备同一码率控制模式效果可能不一样
  * @return {0} if successful
  */
  public native int SetVideoHWEncoderBitrateMode(long handle, int hw_bitrate_mode);

视频硬编码复杂度设置:

  /*
   * 设置视频硬编码复杂度, 安卓5.0及以上支持
   * @param hw_complexity: -1表示不设置, 请参考:android.media.MediaCodecInfo.EncoderCapabilities.getComplexityRange() 和 android.media.MediaFormat.KEY_COMPLEXITY
   * 注意硬编码和手机硬件有关,部分手机可能不支持此设置
   * @return {0} if successful
   */
  public native int SetVideoHWEncoderComplexity(long handle, int hw_complexity);

视频硬编码质量设置:

  /*
   * 设置视频硬编码质量, 安卓9及以上支持, 仅当硬编码器码率控制模式(BitrateMode)是CQ(constant-quality mode)时才有效
   * @param hw_quality: -1表示不设置, 请参考:android.media.MediaCodecInfo.EncoderCapabilities.getQualityRange() 和 android.media.MediaFormat.KEY_QUALITY
   * 注意硬编码和手机硬件有关,部分手机可能不支持此设置
   * @return {0} if successful
   */
  public native int SetVideoHWEncoderQuality(long handle, int hw_quality);

H.264硬编码Profile设置:

  /*
   * 设置H.264硬编码Profile, 安卓7及以上支持
   * @param hw_avc_profile: 0表示使用默认值, 0x01: Baseline, 0x02: Main, 0x08: High, 0x10000: ConstrainedBaseline, 0x80000: ConstrainedHigh;
   * 注意: ConstrainedBaseline 和 ConstrainedHigh 可能多数设备不支持,
   * H.264推荐使用 High 或者 ConstrainedHigh, 如果您使用的手机硬解码解不了,那还是设置Baseline
   * 如果设置的Profile硬编码器不支持,应编码器会使用默认值
   * 具体参考:android.media.MediaCodecInfo.CodecProfileLevel
   * @return {0} if successful
   */
  public native int SetAVCHWEncoderProfile(long handle, int hw_avc_profile);

H.264硬编码Level设置:

  /*
   * 设置H.264硬编码Level, 这个只有在设置了Profile的情况下才有效, 安卓7及以上支持
   * @param hw_avc_level: 0表示使用默认值, 0x100: Level3, 0x200: Level3.1, 0x400: Level3.2,
   * 0x800: Level4, 0x1000: Level4.1, 0x2000: Level4.2,
   * 0x4000: Level5, 0x8000: Level5.1,  0x10000: Level5.2,
   * 0x20000: Level6, 0x40000: Level6.1,  0x80000: Level6.2,
   * 如果设置的level太高硬编码器不支持,SDK内部会做相应调整
   * 注意: 640*480@25fps最小支持的是Level3, 720p最小支持的是Level3.1, 1080p最小支持的是Level4
   * 具体参考:android.media.MediaCodecInfo.CodecProfileLevel
   * @return {0} if successful
   */
  public native int SetAVCHWEncoderLevel(long handle, int hw_avc_level);

视频硬编码最大码率设置:

  /*
   * 设置视频硬编码最大码率, 安卓没有相关文档说明, 所以不建议设置,
   * @param hw_max_bitrate: 每秒最大码率, 单位bps
   * @return {0} if successful
   */
  public native int SetVideoHWEncoderMaxBitrate(long handle, long hw_max_bitrate);

上层调用代码如下:

        if(videoEncodeType == 1)  {
            int h264HWKbps = setHardwareEncoderKbps(true, videoWidth, videoHeight);
            h264HWKbps = h264HWKbps*fps/25;
            Log.i(TAG, "h264HWKbps: " + h264HWKbps);
            int isSupportH264HWEncoder = libPublisher
                    .SetSmartPublisherVideoHWEncoder(publisherHandle, h264HWKbps);
            if (isSupportH264HWEncoder == 0) {
                libPublisher.SetNativeMediaNDK(publisherHandle, 0);
                libPublisher.SetVideoHWEncoderBitrateMode(publisherHandle, 1); // 0:CQ, 1:VBR, 2:CBR
                libPublisher.SetVideoHWEncoderQuality(publisherHandle, 39);
                libPublisher.SetAVCHWEncoderProfile(publisherHandle, 0x08); // 0x01: Baseline, 0x02: Main, 0x08: High
                // libPublisher.SetAVCHWEncoderLevel(publisherHandle, 0x200); // Level 3.1
                // libPublisher.SetAVCHWEncoderLevel(publisherHandle, 0x400); // Level 3.2
                // libPublisher.SetAVCHWEncoderLevel(publisherHandle, 0x800); // Level 4
                libPublisher.SetAVCHWEncoderLevel(publisherHandle, 0x1000); // Level 4.1 多数情况下,这个够用了
                //libPublisher.SetAVCHWEncoderLevel(publisherHandle, 0x2000); // Level 4.2
                // libPublisher.SetVideoHWEncoderMaxBitrate(publisherHandle, ((long)h264HWKbps)*1300);
                Log.i(TAG, "Great, it supports h.264 hardware encoder!");
            }
        }
        else if (videoEncodeType == 2) {
            int hevcHWKbps = setHardwareEncoderKbps(false, videoWidth, videoHeight);
            hevcHWKbps = hevcHWKbps*fps/25;
            Log.i(TAG, "hevcHWKbps: " + hevcHWKbps);
            int isSupportHevcHWEncoder = libPublisher
                    .SetSmartPublisherVideoHevcHWEncoder(publisherHandle, hevcHWKbps);
            if (isSupportHevcHWEncoder == 0) {
                libPublisher.SetNativeMediaNDK(publisherHandle, 0);
                libPublisher.SetVideoHWEncoderBitrateMode(publisherHandle, 0); // 0:CQ, 1:VBR, 2:CBR
                libPublisher.SetVideoHWEncoderQuality(publisherHandle, 39);
                // libPublisher.SetVideoHWEncoderMaxBitrate(publisherHandle, ((long)hevcHWKbps)*1200);
                Log.i(TAG, "Great, it supports hevc hardware encoder!");
            }
        }

从实际测试来看,基于MediaCodec的硬编码相对软编来说,虽然不一定有软编码率各个方面控制的那么好,但是正确的调用MediaCodec硬编,可以显著提高视频编码能力,让1080P甚至更高分辨率帧率码率的视频编码,效率更高。

相关文章
|
2月前
|
Android开发
安卓SO层开发 -- 编译指定平台的SO文件
安卓SO层开发 -- 编译指定平台的SO文件
33 0
|
6天前
|
Android开发
Android RIL 动态切换 4G 模块适配
Android RIL 动态切换 4G 模块适配
10 0
|
1月前
|
运维 监控 Java
应用研发平台EMAS产品常见问题之安卓构建版本失败如何解决
应用研发平台EMAS(Enterprise Mobile Application Service)是阿里云提供的一个全栈移动应用开发平台,集成了应用开发、测试、部署、监控和运营服务;本合集旨在总结EMAS产品在应用开发和运维过程中的常见问题及解决方案,助力开发者和企业高效解决技术难题,加速移动应用的上线和稳定运行。
|
1月前
|
运维 监控 Android开发
应用研发平台EMAS常见问题之安卓push的离线转通知目前无法收到如何解决
应用研发平台EMAS(Enterprise Mobile Application Service)是阿里云提供的一个全栈移动应用开发平台,集成了应用开发、测试、部署、监控和运营服务;本合集旨在总结EMAS产品在应用开发和运维过程中的常见问题及解决方案,助力开发者和企业高效解决技术难题,加速移动应用的上线和稳定运行。
25 1
|
2月前
|
XML Java API
安卓逆向 -- Xposed模块编写
安卓逆向 -- Xposed模块编写
19 0
|
Android开发
Android RTMP直播推流方案选择
1. 技术科普: RTMP是Real Time Messaging Protocol(实时消息传输协议)的首字母缩写。
2439 0
|
7天前
|
Linux 编译器 Android开发
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
在Linux环境下,本文指导如何交叉编译x265的so库以适应Android。首先,需安装cmake和下载android-ndk-r21e。接着,下载x265源码,修改crosscompile.cmake的编译器设置。配置x265源码,使用指定的NDK路径,并在配置界面修改相关选项。随后,修改编译规则,编译并安装x265,调整pc描述文件并更新PKG_CONFIG_PATH。最后,修改FFmpeg配置脚本启用x265支持,编译安装FFmpeg,将生成的so文件导入Android工程,调整gradle配置以确保顺利运行。
26 1
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
|
30天前
|
Java Android开发
Android 开发获取通知栏权限时会出现两个应用图标
Android 开发获取通知栏权限时会出现两个应用图标
14 0
|
4天前
|
数据库 Android开发 开发者
安卓应用开发:构建高效用户界面的策略
【4月更文挑战第24天】 在竞争激烈的移动应用市场中,一个流畅且响应迅速的用户界面(UI)是吸引和保留用户的关键。针对安卓平台,开发者面临着多样化的设备和系统版本,这增加了构建高效UI的复杂性。本文将深入分析安卓平台上构建高效用户界面的最佳实践,包括布局优化、资源管理和绘制性能的考量,旨在为开发者提供实用的技术指南,帮助他们创建更流畅的用户体验。
|
21天前
|
XML 开发工具 Android开发
构建高效的安卓应用:使用Jetpack Compose优化UI开发
【4月更文挑战第7天】 随着Android开发不断进化,开发者面临着提高应用性能与简化UI构建流程的双重挑战。本文将探讨如何使用Jetpack Compose这一现代UI工具包来优化安卓应用的开发流程,并提升用户界面的流畅性与一致性。通过介绍Jetpack Compose的核心概念、与传统方法的区别以及实际集成步骤,我们旨在提供一种高效且可靠的解决方案,以帮助开发者构建响应迅速且用户体验优良的安卓应用。