基于RTMP协议的监控系统的搭建

客户端(RTMP系列四)

2017-07-29  本文已影响75人  onesixthree

客户端设计

  本项目为满足多平台监控需求,设计了Linux、Android和网页客户端。其中网页客户端基于JWplayer。Linux与Android客户端需要完成的功能主要有以下几部分:

  1. 完成与服务器的通信,接收RTMP数据;
  2. 从获取的FLV数据中提取H264 Nalu单元数据;
  3. 完成H264的解码,获取YUV数据;
  4. 将YUV数据通过SDL(Android系统通过Opengl)显示到屏幕上。

  客户端的的架构图如图1-1所示。


客户端架构

  接收RTMP数据部分由RMTP协议模块负责,在介绍服务器与客户端通信有详细介绍,接收从服务器发送过来的FLV数据。FLV解析模块从FLV中提取Nalu单元,放入共享内存,然后调用FFmepg的解码接口从共享内存中读取H264数据解码为YUV数据,最后将YUV数据通过显示模块显示到屏幕上。

客户端的实现

Linux下播放器的实现

RTMP协议模块的实现

  按照Linux客户端的设计流程,首先我们需要完成的是RTMP协议模块。客户端需要用到Librtmp来接收RTMP流数据,函数的执行流程如图1-2所示。

接收数据流程图

  函数RTMP_Alloc()、RTMP_Init()在RTMP服务器中已经使用过,用来初始化用于RTMP通信的RMTP结构体。接下来的RTMP_Connect()、RTMP_ConnectStream()、RTMP_Read()实现和RTMP服务器建立RTMP流媒体传输的握手、连接、创建流以及播放过程。

FLV解析模块的实现

  本项目实现的FLV解析模块设计的初衷是在包含H264数据的FLV流中提取出H264 Nalu数据。在第二章中有介绍过FLV流的结构,但是通过对FLV二进制流的分析后发现,一个video Tag数据中不仅仅包含视频数据,而且还包含访问分割符。因此,在提取Nalu数据时,需要对video tag中不同的信息进行区别。在本模块中,对非SPS、PPS、I帧和P帧的数据进行舍弃。
  首先对从RTMP传递过来的FLV Tag数据buf进行分析,如果时Tag数据包含的是视频数据就进行下一步分析,如果不是则舍弃。如果获得的是视频数据,那么对Video Tag的数据部分进行分析,首先根据前两个字符来区分关键帧和非关键帧,再保存Nalu长度,分析Nalu包的前两个字符,如果是单元分割符或者SEI则舍弃,如果是数据帧,则加上Nalu头即0x00000001,然后送入缓冲区,等待解码播放。核心代码如下:

nalu_type=buf[naltail_pos+1]&0xff;
if(nalu_type==1)
{
    naltail_pos+=5;
    while(naltail_pos<nRead-5)
    {
        naltail_pos++;
        size=(buf[naltail_pos++]&0xff)*65536;
        size+=(buf[naltail_pos++]&0xff)*256;
        size+=buf[naltail_pos++]&0xff;
        nalu_type=buf[naltail_pos]&0xff;
        if(nalu_type==9||nalu_type==6)
        {
            naltail_pos+=size;
            continue;
        }
        body = (char*)malloc(size+4);
        memset(body,0,size+4);
        i=0;
        body[i++] = 0x00;
        body[i++] = 0x00;
        body[i++] = 0x00;
        body[i++] = 0x01;
        memcpy(&body[i],buf+naltail_pos,size);
        int error;
        error=decode(handler,body,size+4);
        free(body);
        naltail_pos+=size;
        break;
    }
}
解码模块的实现

  解码模块和编码模块一样,使用到了FFmpeg,和编码流程相类似,本项目的解码流程如图1-3所示。

Ffmpeg解码流程图

流程图中关键函数的作用:

显示模块的实现

  Linux客户端的显示模块基于SDL实现,SDL模块主要的功能是将YUV图像显示到屏幕上面,由于是从服务器端接收数据,时间戳不用我们来设置,每接收一帧视频数据就调用解码端和显示端进行解码显示。解码和显示是连接在一起的,每解码得到YUV数据就立即通过FFmpeg函数提供的sws_scale()函数对其进行图像拉伸,以适用于显示,最后调用SDL_UpdateTexture ()函数显示到SDL开辟的View当中。
  最后首先运行RTMP服务器,然后运行Linux客户端,播放监控数据,运行如图1-4所示。

Linux客户端
上一篇下一篇

猜你喜欢

热点阅读