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

news/2025/1/20 4:39:54/

   实际项目中经常遇到两种场景,第一种从无人机拿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);// 图像等比例缩放或铺满viewlib_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.ppmy.cn/news/71371.html

相关文章

8年开发经验,浅谈 API 管理

随着信息化飞速增长的还有各信息系统中的应用接口(API),API作为信息系统内部及不同信息系统之间进行数据传输的渠道,其数量随着软件系统的不断庞大而呈指数型增长,如何管理这些API已经在业界变得越来越重要&#xff0c…

无公网IP,公网SSH可远程访问家中的树莓派

文章目录 前言如何通过 SSH 连接到树莓派步骤1. 在 Raspberry Pi 上启用 SSH步骤2. 查找树莓派的 IP 地址步骤3. SSH 到你的树莓派步骤 4. 在任何地点访问家中的树莓派4.1 安装 Cpolar内网穿透4.2 cpolar进行token认证4.3 配置cpolar服务开机自启动4.4 查看映射到公网的隧道地址…

数据库的恢复技术

更好的阅读体验 存储器结构 分类 1、易失性存储器:内存、高速缓冲存储器 2、非易失性存储器:磁盘、磁带 3、稳定存储器:理想的存储器,其中信息永不丢失 稳定存储器的实现 要实现稳定存储器,就要在多个非易失性存储…

NestedFormer:用于脑肿瘤分割的嵌套模态感知Transformer

文章目录 NestedFormer: Nested Modality-AwareTransformer for Brain Tumor Segmentation摘要方法Global Poolformer EncoderNested Modality-Aware Feature AggregationModality-Sensitive Gating 实验结果 NestedFormer: Nested Modality-AwareTransformer for Brain Tumor …

算力网络安全

算力网络安全 1. 算力网络简介1.1 基本概念1.2 应用场景 2. 算力网络安全需求3. 算力网络安全架构3.1 算力网络参考架构3.2 资源层安全3.3 控制层和编排管理层安全3.4 服务层安全 4. 算力网络安全关键技术4.1 安全计算4.2 安全编排4.3 数据溯源4.4 可信内生4.5 操作审计4.6 安全…

最“拼爹妈”的美国大学TOP10,什么是Legacy 录取?

Legacy的直译是遗产的意思,父母和大学的关系,就像家庭的遗产一样,可以传递给孩子一代(有时候,亲哥哥,亲姐姐也会被算作是 legacy)。有的大学祖父母如果是校友,也会算作 legacy。再远…

Camtasia Studio2023最新版喀秋莎电脑录制屏幕编辑器

不管是在我们平日的工作当中,还是生活当中,camtasia studio可以方便地进行屏幕操作的录制和配音、视频的剪辑和过场动画、添加说明字幕和水印、制作视频封面和菜单、视频压缩和播放。 你都会因为一些事情,从而需要进行录屏的需求。而Camtasi…

Robust 2.0:支持Android R8的升级版热修复框架

2016年,我们对美团Android热更新方案Robust的技术原理做了详细介绍。近几年,Google 推出了新的代码优化混淆工具R8,Android 热修复补丁制作依赖二次构建包和线上包对比,需要对Proguard切换到R8提前进行适配和改造,本文…