欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

用android实现GB28181监控客户端app

程序员文章站 2022-03-17 14:13:32
...

      武汉一直笼罩在新冠状病毒的疫情中,我不喜欢在朋友圈拿疫情去炒作,但我知道,如果真的智能AI智能识别,智能机器人,自动驾驶,远程分级诊疗等热门技术如果只要有一样能够落地能够应用,武汉的疫情不会如此被动。所以一切不以应用为目的的技术炒作都是耍流氓。

      待在家里无法出门,解决了食物的储备后,无聊至极,于是想着干脆开发GB28181的客户端手机版APP以度过闲暇时光。下面开始言归正传。

      我有过做android解码器的经历,那是在上家公司,当时从0开始,那是android版本主流是4.4.2,刚开始用ffmpeg解码,opengles显示渲染,音频用opensl,native c++实现,后来要多路解码,支持H265解码,使用硬解。公司做军品,硬件固定型号,为了追求低延时直接从源码上修改了编译,基本是针对指定硬件的方案,兼容性差。

      而本次GB28181移动客户端的开发,解码和渲染是少不了的。对于这种手机APP,我首先考虑的是性能和兼容性。而且现在手机版本都到android 10了,所以兼容性十分重要。

      GB28181协议这一块因为之前PC客户端已实现,基于esosip和osp库,用c++开发的,所以直接移植到android版即可,在android上关键需要实现解码和音视频的渲染播放。

      当然我们还是得选择硬解码,android如果硬解码和渲染是一个管线式的流程,可以理解为通过解码后数据块在GPU的显存,通过指针直接丢向ANativeWindow显示,ANativeWindow是natvie c++层的对象,其实它与android java层的surfaceview是关联的,通过如下代码:

private SurfaceView  sfvideoview;
SurfaceHolder sfholder;
long     natviewindow = 0;

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sfvideoview = (SurfaceView) findViewById(R.id.videoView);
        sfholder = sfvideoview.getHolder();
        sfholder.addCallback(new SurfaceHolder.Callback()
        {
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {

            }

            public void surfaceCreated(SurfaceHolder holder) {
                if(natviewindow == 0)
                  natviewindow = GbtClientJni.gbtclient_createnativewindow                       
                  (sfholder.getSurface());
            }
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format,
                                       int width, int height) {
            }
        });
    }    

GbtClientJni.gbtclient_createnativewindow函数就是传的surfaceview的surface,该函数必须在surfaceCreated中,因为该函数属于在glrender线程中,渲染相关流程必须要oepngles的rander线程中。我们把surface传入到native层,通过ANativeWindow_fromSurface函数可以得到ANativeWindow,而在底层,ANativeWindow就是渲染解码数据的载体。

ANativeWindow  *anw = NULL;
anw = ANativeWindow_fromSurface(env, jsurface);

这样就完成了视频渲染的上下层衔接。

     对于目前android音频的播放,好像还是两种方案,audiotrack和opensl,我依然选择使用opensl,因为audiotrack靠近底层了,担心其兼容性。对于接口都很简单,无非都是回调函数,然后往里面塞数据。首先取出解码后的音频数据,可以用ffmpeg解码,然后调用opensl的接口:

SLresult result = (*bq)->Enqueue(bq, m_pAudioBuffer, m_nAudioBufferConsumed);

    基于有PC版GB28181客户端的基础,解决了移动端设备相关的差异性后,GB28181移动客户端就开发完毕了,如下图:

用android实现GB28181监控客户端app

用android实现GB28181监控客户端app

 

更多信息

e-mail: aaa@qq.com

tel: 13971177602

web:www.founu.com