Android平台如何实现外部编码后(H.264/H.265)数据实时预览播放

简介: 我们在对接开发者的时候,遇到这样的诉求:除了正常的RTMP、RTSP直播播放外,有些硬件设备输出编码后(H.264/H.265)的数据,比如无人机或类似硬件产品,回调出来的H.264/H.265数据,除了正常转推到RTMP、轻量级RTSP服务或GB28181外,还需要本地预览甚至重新对数据做二次处理,基于这样的场景诉求,我们开发了外部编码后数据实时预览播放模块。

技术背景

我们在对接开发者的时候,遇到这样的诉求:除了正常的RTMP、RTSP直播播放外,有些硬件设备输出编码后(H.264/H.265)的数据,比如无人机或类似硬件产品,回调出来的H.264/H.265数据,除了正常转推到RTMP、轻量级RTSP服务或GB28181外,还需要本地预览甚至重新对数据做二次处理,基于这样的场景诉求,我们开发了外部编码后数据实时预览播放模块。

接口设计

废话不多说,外部H.264/H.265投递接口设计如下:

  // SmartPlayerJniV2.java
    // Author: daniusdk.com
    /**
   * 投递视频包给外部Live Source
   *
   * @param codec_id: 编码id, 当前仅支持H264和H265, 1:H264, 2:H265
   *
   * @param packet: 视频数据, ByteBuffer必须是DirectBuffer, 包格式请参考H264/H265 Annex B Byte stream format, 例如:
   *                0x00000001 nal_unit 0x00000001 ...
   *                H264 IDR: 0x00000001 sps 0x00000001 pps 0x00000001 IDR_nal_unit .... 或 0x00000001 IDR_nal_unit ....
   *                H265 IDR: 0x00000001 vps 0x00000001 sps 0x00000001 pps 0x00000001 IDR_nal_unit .... 或 0x00000001 IDR_nal_unit ....
   *
   * @param offset: 偏移量
   * @param size: packet size
   * @param timestamp_ms: 时间戳, 单位毫秒
   * @param is_timestamp_discontinuity: 是否时间戳间断,0:未间断,1:间断
   * @param is_key: 是否是关键帧, 0:非关键帧, 1:关键帧
   * @param extra_data: 可选参数,可传null, 对于H264关键帧包, 如果packet不含sps和pps, 可传0x00000001 sps 0x00000001 pps
   *                    ,对于H265关键帧包, 如果packet不含vps,sps和pps, 可传0x00000001 vps 0x00000001 sps 0x00000001 pps
   * @param extra_data_size: extra_data size
   * @param width: 图像宽, 可传0
   * @param height: 图像高, 可传0
   *
   * @return {0} if successful
   */
  public native int PostVideoPacketByteBuffer(long handle, int codec_id,
                    java.nio.ByteBuffer packet, int offset, int size, long timestamp_ms, int is_timestamp_discontinuity, int is_key,
                    byte[] extra_data, int extra_data_size, int width, int height);
  /*
  * 请参考 PostVideoPacketByteBuffer说明
   */
  public native int PostVideoPacketByteArray(long handle, int codec_id,
                        byte[] packet, int offset, int size, long timestamp_ms, int is_timestamp_discontinuity, int is_key,
                        byte[] extra_data, int extra_data_size, int width, int height);

PostVideoPacketByteBuffer()和PostVideoPacketByteArray()接口设计基本类似,唯一的区别在于,一个数据类型是ByteBuffer,一个是byte数组。


其中codec_id,系编码id,目前仅支持H.264和H.265类型。


packet视频数据,需要注意的是,ByteBuffer必须是DirectBuffer, 包格式请参考H264/H265 Annex B Byte stream format, 例如:

0x00000001 nal_unit 0x00000001 ...
H264 IDR: 0x00000001 sps 0x00000001 pps 0x00000001 IDR_nal_unit .... 或 0x00000001 IDR_nal_unit ....
H265 IDR: 0x00000001 vps 0x00000001 sps 0x00000001 pps 0x00000001 IDR_nal_unit .... 或 0x00000001 IDR_nal_unit ....

extra_data: 可选参数,可传null, 对于H264关键帧包,如果packet不含sps和pps,可传0x00000001 sps 0x00000001 pps,对于H265关键帧包,如果packet不含vps,sps和pps, 可传0x00000001 vps 0x00000001 sps 0x00000001 pps

调用逻辑

下面我们看看逻辑调用,本文基于大牛直播SDK的RTSP|RTMP转RTMP推送demo做展示,先拉取到RTSP或RTMP的流数据,然后把拉取到的H.264/H.265数据回调上来,调用我们外部live source数据接口,投递到底层,实现实时数据的播放,如果外部数据,可以忽略拉流这块,直接在数据回调的地方,调live source数据投递接口即可。

2606e7a6ad4248e8a243cc961c9ce4ba.jpg

数据投递:

    public void onVideoDataCallback(int ret, int video_codec_id, int sample_size, int is_key_frame, long timestamp, int width, int height, long presentation_timestamp)
    {
      //Log.i("onVideoDataCallback", "ret: " + ret + ", video_codec_id: " + video_codec_id + ", sample_size: " + sample_size + ", is_key_frame: "+ is_key_frame +  ", timestamp: " + timestamp +
      //    ",presentation_timestamp:" + presentation_timestamp);
      if ( video_buffer_ == null)
        return;
      video_buffer_.rewind();
      if (0 == ret && ex_live_src_player_handle_ !=0) {
        libPlayer.PostVideoPacketByteBuffer(ex_live_src_player_handle_, video_codec_id, video_buffer_, 0, sample_size, timestamp, 0, is_key_frame, null,0, 0, 0);
      }
    }


启动外部数据播放:


可以看到,外部数据可以用软解码或硬解码播放,如果分辨率很大可以考虑特定机型硬解码,外部数据播放,依然可以设置铺满或按比例显示。如果需要针对数据做二次处理,也可以把设置RGB或YUV数据回调,对回调后的数据做二次处理,甚至二次编码(如做视频分析、实时水印等)。

  private long start_ex_live_src_player(SmartPlayerJniV2 lib_player, Context context, SurfaceView surface_view, boolean is_hardware_decoder) {
    if (null ==lib_player || null == context || null == surface_view)
      return 0;
    long handle = lib_player.SmartPlayerOpen(context);
    if (0 == handle) {
      Log.e(TAG, "start_ex_live_src_player open player failed");
      return 0;
    }
    // 设置0, 尽可能降低预览延时
    lib_player.SmartPlayerSetBuffer(handle, 0);
    lib_player.SmartPlayerSetUrl(handle, "ntexternal://livesource/implemention0");
    lib_player.SmartPlayerSetSurface(handle, surface_view);
    // 图像等比例缩放或铺满view
    lib_player.SmartPlayerSetRenderScaleMode(handle, 1);
    lib_player.SmartPlayerSetFastStartup(handle, 1);
    // 不要播放音频,静音就好
    lib_player.SmartPlayerSetMute(handle, 1);
    // 大分辨率可能需要硬解,小分辨率推荐软解,硬解延时可能大些
    if (is_hardware_decoder) {
      lib_player.SetSmartPlayerVideoHevcHWDecoder(handle, 1);
      lib_player.SetSmartPlayerVideoHWDecoder(handle, 1);
    }
    // 有些场景可能需要解码出来的图像用来做分析或重新编码
    // 这里可以设置yuv或rgb callback, 把图像给Caller
    // lib_player.SmartPlayerSetExternalRender(handle, new RGBAExternalRender());
    // lib_player.SmartPlayerSetExternalRender(handle, new I420ExternalRender());
    if (0 == lib_player.SmartPlayerStartPlay(handle))
      return handle;
    lib_player.SmartPlayerClose(handle);
    return 0;
  }

停止外部数据播放:

  private void stop_ex_live_src_play(SmartPlayerJniV2 lib_player, long handle) {
    if (null == lib_player)
      return;
    if (0 == handle)
      return;
    lib_player.SmartPlayerStopPlay(handle);
    lib_player.SmartPlayerClose(handle);
  }


总结

Android平台外部编码后H.264/H.265数据实时预览播放,在一些传统行业里面,可以说是意义非常大,除了可以预览回调过来的数据外,还可以针对外部数据做二次视频分析、二次编辑投递(实时水印、字符叠加等),感兴趣的开发者可以试试看。

相关文章
|
10月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
930 4
|
2月前
|
安全 数据库 Android开发
在Android开发中实现两个Intent跳转及数据交换的方法
总结上述内容,在Android开发中,Intent不仅是活动跳转的桥梁,也是两个活动之间进行数据交换的媒介。运用Intent传递数据时需注意数据类型、传输大小限制以及安全性问题的处理,以确保应用的健壯性和安全性。
125 11
|
2月前
|
监控 Android开发 数据安全/隐私保护
批量发送短信的平台,安卓群发短信工具插件脚本,批量群发短信软件【autojs版】
这个Auto.js脚本实现了完整的批量短信发送功能,包含联系人管理、短信内容编辑、发送状态监控等功能
|
4月前
|
存储 XML Java
Android 文件数据储存之内部储存 + 外部储存
简介:本文详细介绍了Android内部存储与外部存储的使用方法及核心原理。内部存储位于手机内存中,默认私有,适合存储SharedPreferences、SQLite数据库等重要数据,应用卸载后数据会被清除。外部存储包括公共文件和私有文件,支持SD卡或内部不可移除存储,需申请权限访问。文章通过代码示例展示了如何保存、读取、追加、删除文件以及将图片保存到系统相册的操作,帮助开发者理解存储机制并实现相关功能。
1010 2
|
6月前
|
存储 编解码 监控
Android平台GB28181执法记录仪技术方案与实现
本文介绍了大牛直播SDK的SmartGBD在执法记录仪场景中的应用。GB28181协议作为视频监控联网的国家标准,为设备互联互通提供规范。SmartGBD专为Android平台设计,支持音视频采集、编码与传输,具备自适应算法和多功能扩展优势。文章分析了执法记录仪的需求,如实时音视频传输、设备管理及数据安全,并详细阐述了基于SmartGBD的技术实现方案,包括环境准备、SDK集成、设备注册、音视频处理及功能扩展等步骤。最后展望了SmartGBD在未来智慧物联领域的广阔应用前景。
217 13
|
6月前
|
存储 编解码 开发工具
Android平台毫秒级低延迟HTTP-FLV直播播放器技术探究与实现
本文详细探讨了在Android平台上实现HTTP-FLV播放器的过程。首先介绍了FLV格式的基础,包括文件头和标签结构。接着分析了HTTP-FLV传输原理,通过分块传输实现流畅播放。然后重点讲解了播放器的实现步骤,涵盖网络请求、数据解析、音视频解码与渲染,以及播放控制功能的设计。文章还讨论了性能优化和网络异常处理的方法,并总结了HTTP-FLV播放器的技术价值,尤其是在特定场景下的应用意义。
240 11
|
6月前
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
|
7月前
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
400 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
9月前
|
IDE 开发工具 Android开发
移动应用开发之旅:探索Android和iOS平台
在这篇文章中,我们将深入探讨移动应用开发的两个主要平台——Android和iOS。我们将了解它们的操作系统、开发环境和工具,并通过代码示例展示如何在这两个平台上创建一个简单的“Hello World”应用。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧,帮助你更好地理解和掌握移动应用开发。
227 17
|
9月前
|
开发框架 Android开发 iOS开发
安卓与iOS开发中的跨平台策略:一次编码,多平台部署
在移动应用开发的广阔天地中,安卓和iOS两大阵营各占一方。随着技术的发展,跨平台开发框架应运而生,它们承诺着“一次编码,到处运行”的便捷。本文将深入探讨跨平台开发的现状、挑战以及未来趋势,同时通过代码示例揭示跨平台工具的实际运用。
293 3