安卓播放H264/H265实时流(安卓实时预览H264/H265 安卓实时预览AVC/HEVC)

news2025/1/18 7:02:44

   实际项目中经常遇到两种场景,第一种从无人机拿H264/H265码流转GB28181等协议,转协议的同时可能还需要实时预览无人机画面; 第二种是安卓接USB外置摄像头, 由于USB2.0传输带宽有限,对于高分辨率图像, 带宽无法满足YUV图像的传输, 摄像头只好先将图像编码成MJPEG,H264或H265等格式再传输。

   对于上述两种场景,安卓拿到的都是已编码的H264或H265码流,这用来转GB28181、RTSP、RTMP和录像存储很方便, 但没法直接实时预览, 实时预览需要先解码,再显示. 这样增加了不少开发成本,为了方便使用, 在我的播放器上直接增加了传H264/H265字节流接口,只要把H264/H265数据传给播放器就好,播放器负责解码(软解或硬解)显示。

  下面先介绍下H264/H265 Annex B Byte stream format:

  字节流格式:字节流由1到多个字节流nal_unit组成.

  字节流nal_unit:{前缀码(0x000001) + nal_unit} 或 {zero_byte(0x00) + 前缀码(0x000001) + nal_unit}. 前缀码为网络字节序.

  需要注意的是: 1.字节流中第一个字节流nal_unit头部可能包含1个或多个leading_zero_8bits(某些安卓硬编码器会出这样的数据); 2.字节流nal_unit单元尾部可能包含一个或多个trailing_zero_8bits.(前后额外加0字节是为了保持字节对齐).

  leading_zero_8bits:  一个0x00字节.

  trailing_zero_8bits: 一个0x00字节.

  对于VPS, SPS, PPS前缀应是 0x00000001(H264只有SPS, PPS), An access unit的第一个nal unit的前缀应是0x00000001.

  字节流NAL单元语法(H264和H265是一致的):

    H264 NAL unit 语法:

    常用的h264 nal_unit_type: 5(IDR), 6(SEI), 7(SPS), 8(PPS).

    H265 NAL unit 语法:

 

   H265的nal_unit_type请参考265文档。

   更详细的描述请参考264和265文档,对于如何调用播放器接口,上面的描述基本够用了,播放器接口如下:

/*
* Copyright (C) 1130758427@qq.com. All rights reserved.
*/

/**
	 * 投递视频包给播放器
	 *
	 * @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);

调用代码:

/*
* Copyright (C) 1130758427@qq.com. All rights reserved.
*/


// 启动播放器
 private long start_play(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, "open player failed");
            return 0;
        }

        // 设置0, 尽可能降低预览延时
        lib_player.SmartPlayerSetBuffer(handle, 0);

        lib_player.SmartPlayerSetUrl(handle, "ntexternal://*******************");

        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_play(SmartPlayerJniV2 lib_player, long handle) {
        if (null == lib_player)
            return;

        if (0 == handle)
            return;

        lib_player.SmartPlayerStopPlay(handle);
        lib_player.SmartPlayerClose(handle);
    }

// 投递H264或H265数据给播放器
public void onVideoDataCallback(int ret, int video_codec_id, int size, int is_key_frame, long timestamp, int width, int height, long presentation_timestamp) {
  if (player_handle_ !=0)
    lib_player_.PostVideoPacketByteBuffer(player_handle_, video_codec_id, video_buffer_, 0, size, timestamp, 0, is_key_frame, null,0, 0, 0);
				
}

   Android也可以用MediaCodec直接解码显示,但MediaCodec坑较多,从一个演示版到稳定版周期较长成本较高,直接在现有成熟稳定的播放器SDK上加接口实现AVC/HEVC实时预览更可行些. 我在Windows上启动一个内置rtsp server流, 安卓拉rtsp流,然后将H264/H265传给播放器显示,延时非常低(毫秒级),并支持H264和H265码流实时切换预览,分辨率实时切换预览,  也支持解码后YUV/RGB数据回调,  实时截图等功能。另外苹果的VideoToolbox只支持AVCC格式,不支持Annex B格式,需要转换后再输入,更多问题联系qq: 1130758427

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/532694.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据的比较

前言 在学习Java过程中&#xff0c;数据的比较是必学的。 对于不同的数据有不同的比较方式。 目录 前言 一、算术比较器 二、equals() 三、Comparable接口 四、Comparator接口 结语 一、算术比较器 算数比较器有&#xff1a;、>、<、>、<、! 但是算数比较器…

win下C++部署深度学习模型之clion配置pytorch+opencv教程记录

win下clion配置pytorch和OpenCV 一、clion配置vs编译器以及测试二、clion配置pytorch2.1、下载libtorch2. 2、环境变量配置2.3、cmakelist.txt编写2.4、main函数测试运行 三、clion配置opencv3.1、源码下载3.2、编译3.3、环境变量配置3.4、cmakelist.txt编写3.5 main函数测试运…

揭 秘~月薪2-3万的程序员一天到底是怎么度过的?

程序员的高薪资&#xff0c;一直是大家热衷讨论的话题&#xff0c;几乎每隔一段时间就会在社交平台被网友们热议一番。 比如这条“月薪2万到3万的程序员的一天是怎么样度过的&#xff1f;”的帖子就一直排在知乎前列。 作为薪资可观的岗位&#xff0c;大家都非常好奇&#xff…

【Fiddler移动端抓包】~抓包不是偷窥,Fiddler教你看透移动应用背后的秘密~

目录 引言 抓包 什么是抓包 哪些场景下需要抓包 Fiddler Fiddler抓包原理 安装 Fiddler移动端抓包 第一步&#xff1a;允许远程计算机连接 第二步&#xff0c;设置手机网络代理 第三步&#xff0c;允许捕获HTTPS连接 第四步&#xff0c;手机安装证书 结语 引言 当…

探寻生机 | 数说故事助力微播易第七届风向大会,研判新风向,洞察新趋势

“过去一年&#xff0c;有的人用ChatGPT谁出具的北京烤鸭图片最准确搞怪&#xff0c;有的人却已经利用虚拟主播单场带货百万&#xff1b;有的人正在被AIGC淘汰&#xff0c;有的人却通过人机协作实现20秒制作100张创意图&#xff1b;有的百万粉丝接不到广告&#xff0c;有的仅靠…

使用python实现微博评论分词与关键词提取(从MySQL数据库中读取数据)

一、实验环境 &#xff08;1&#xff09;Windows 操作系统&#xff1b; &#xff08;2&#xff09;PyCharm 2019.1。 &#xff08;3&#xff09;数据库用户名为 root&#xff0c;密码为 123456. (4) 学校机房电脑&#xff0c;带有mysql 二、获取数据库信息 &#xff08;1&a…

【Linux从入门到精通】进程的基本概念

我们通过对上篇文章冯诺依曼体系结构对硬件进行讲解后&#xff0c; 本篇文章会对进程进行深入讲解。同时会讲解PCB&#xff08;进程控制块&#xff09;。希望本篇文章内容会对你有所帮助。 文章目录 一、再次理解操作系统 1、1 操作系统的作用 1、2 操作系统的管理 二、进程基本…

【Linux】12. 模拟实现shell

回顾 在之前的学习过程中&#xff0c;我们掌握了进程的相关概念&#xff0c;冯诺依曼体系结构&#xff0c;进程地址空间概念&#xff0c;进程状态&#xff0c;进程控制&#xff0c;进程退出&#xff0c;进程替换…等等一系列的基础知识&#xff0c;这些基础知识让我们清楚的知…

Qt6之字符串类内存分配新变化——16的次方增加

qt提供了比标准c string更强大&#xff0c;更丰富&#xff0c;更实用的字符串类QString&#xff0c;它的主要功能22个已经在之前逐一分析过&#xff0c;感兴趣的可前往以下链接查看&#xff0c;本文主要重点分析下qt在字符串类上面做的优化&#xff0c;主要是两个方面&#xff…

当产品进化遇见亿元福利,华帝携手人民日报为消费复苏添了一把火

这个五一黄金周&#xff0c;消费复苏的热火彻底被点燃。统计数据显示&#xff0c;2023年“五一”假期累计超过2.74亿人次出游&#xff0c;消费市场恢复到2019年同期水平。久违的“人间烟火气”再度回归。 除了旅游市场的火爆&#xff0c;同样助燃消费市场的还有全民“厨房焕新…

使用Vue+Python基于卷积神经网络前后端分离实现蔬菜种类预测系统

使用VuePython基于卷积神经网络前后端分离实现蔬菜种类预测系统 一、实现效果 1、种类预测界面 2、数据处理分析界面 3、网络模型界面 4、结果分析界面 二、需求分析 用户通过上传待预测图片到系统&#xff0c;系统预测出该图片对应的蔬菜种类&#xff0c;并且提示用户预测信…

基于Web的智慧储能电站3D可视化管理平台

电能作为现代社会的运转和发展的基础&#xff0c;是民生最基本的保障&#xff0c;其稳定性对国家经济发展至关重要。 建设背景 电力系统是一个稳态平衡系统&#xff0c;发电站的总发电功率需要等于用户端的总发电功率。如果两者不一致&#xff0c;就会导致整个电力系统的不稳…

[PyTorch][chapter 34][池化层与采样]

前言&#xff1a; 这里主要讲解一下卷积神经网络中的池化层与采样 目录 DownSampleMax poolingavg poolingupsampleReLu 1&#xff1a; DownSample 下采样,间隔一定行或者列进行采样&#xff0c;达到降维效果 早期LeNet-5 就采样该采样方式。 LeNet-5 2 Max pooling 最大值采样…

【28岁了,没有职业规划,没有目标,朋友推荐学云计算技术,能成吗?】

一般来说&#xff0c;当然可以的。云计算是一个不断发展的行业&#xff0c;不考虑年龄的因素&#xff0c;任何人都可以学习和掌握云计算的技能。28岁的年龄入行云计算是可行的&#xff0c;年龄方面还是符合企业的要求&#xff0c;而且云计算领域的发展趋势也显示出越来越多的企…

RIDGID里奇金属管线检测仪故障定位仪维修SR-20KIT

里奇RIDGID管线定位仪/检测仪/探测仪维修SR-20 SR-24 SR-60 美国里奇SeekTech SR-20管线定位仪对于初次使用定位仪的用户或经验丰富的用户&#xff0c;都同样可以轻易上手使用SR-20。SR-20提供许多设置和参数&#xff0c;使得大多数复杂的定位工作变得很容易。此外&#xff0c…

国内ChatGPT使用教程

猿说AI助手系统基于中国开源项目进行开发&#xff0c;由神诺网络科技工作室提供技术支持&#xff0c;后面我们会跟随官方持续更新。对话默认运行的是3.5-turbo模型&#xff0c;绘画采用Midjourney接口&#xff0c;待更新百度文心、通义千问、微信WeLM等。本系统仅用于技术研究&…

【k8s】【ELK】基于节点DaemonSet运行日志Agent实践【待写】

1.日志收集场景分析与说明 部署架构说明 对于那些将日志输出到&#xff0c;stdout与stderr的Pod&#xff0c; 可以直接使用DaemonSet控制器在每个Node节点上运行一个 <font colorred>filebeat、logstash、fluentd </font>容器进行统一的收集&#xff0c;而后写入…

论文阅读-DGM4-Detecting and Grounding Multi-Modal Media Manipulation

一、论文信息 论文名称&#xff1a;Detecting and Grounding Multi-Modal Media Manipulation 作者团队&#xff1a;南洋理工哈工大 Github:https://github.com/rshaojimmy/MultiModal-DeepFake 项目主页&#xff1a;https://rshaojimmy.github.io/Projects/MultiModal-DeepF…

在EasyCVR平台中添加设备提示成功但不显示是什么原因?

EasyCVR视频融合平台基于云边端智能协同架构&#xff0c;具有强大的数据接入、处理及分发能力&#xff0c;平台支持海量视频汇聚管理&#xff0c;可支持多协议接入&#xff0c;包括市场主流标准协议与厂家私有协议及SDK&#xff0c;如&#xff1a;国标GB28181、RTMP、RTSP/Onvi…

JECloud 运行前端模块所遇到的问题 汇总

1.依赖安装问题 官网 JECLoud 前端打包部署 1.1 部署前 注意 可以先下载 jecloud-libs 项目 尝试 部署安装 node版本不能过高&#xff01;选择node v14.17.5 版本 在部署前 如果当前node版本过高可以使用 nvm工具 切换到低版本&#xff0c; 但是需要注意的是 切换版本时 …