RTMP视频连线互动rtmp直播基于RTMP协议的监控系统的搭建

视频采集与编码(RTMP系列二)

2017-07-13  本文已影响207人  onesixthree

1.视频采集与编码模块设计

本工程是基于Linux系统实现,在Linux中,读取摄像头数据需要用到V4L2 API接口,从摄像头获取的原始数据是YUV422格式,而利用Flash播放视频数据时,需要最终解码为YUV420格式,所以将原始的YUV422数据映射到用户缓冲区后,需要通过转换函数将YUV422转换为YUV420数据。再通过FFmpeg提供的通用编码接口调用X264开源库,将YUV420数据编码压缩为H264数据。

视频采集与编码模块主要功能有:

(1)采集usb摄像头数据,格式为yuv422;

(2)将yuv422数据转为yuv420,将获取的yuv420数据通过目标检测与跟踪模块进行处理。

(3)调用x264库对其进行编码(如果服务器采用的是基于云平台的RTMP服务器,会将编码后的数据直接发送给服务器);

视频采集与编码模块如图1-1所示。

图1-1视频采集与编码模块

2.H264压缩编码过程及实现

本工程使用的是软编码方式对YUV数据进行编码,基于X264开源库,在Linux和Android系统下,可以编译包含了X264库的FFmpeg的动态库。最后基于FFmpeg的提供的编码API将YUV420数据编码为H264数据。使用FFmpeg库可以为用户提供基于不同编码库的相同编码API,便与统一管理以及以后对编码技术的升级,Hevc编码技术的出现,为4K传输的实现提供可能,在不久的将来,当编码技术与硬件条件达标之后,我们可以方便的为工程升级到Hevc编码技术。

FFmpeg编码视频的流程如图2-1所示。

图2-1 FFmpeg编码流程图

使用FFmpeg获取我们所需的格式,首先通过av_register_all()函数向系统注册FFmpeg所支持的所有编码库,将FFmpeg所支持的所有编码格式注册到工程环境当中,然后我们通过avcodec_find_encoder()函数来寻找选定我们所需要的编码格式,接下来为编码前和编码后数据分配一些数据的缓存空间,最后启动采集编码,实时的编码获取的视频数据,将编码后的数据放到缓存中。下面介绍FFmpeg解码流程中需要用到的函数。

av_register_all():该函数是ffmpeg注册复用器、编码器等的函数。

avformat_alloc_output_context2():该函数为结构体AVFormatContext进行初始化,这个结构体主要记录集采到的视频文件的信息参数,主要有文件格式、视音频流的个数、视音频流、时长等。

avio_open():打开输出文件,可以是本地文件,也可以输出的URL地址。

av_new_stream():创建输出码流的AVStream,可以是视频流,或者是音频流。

avcodec_find_encoder():根据事先设置好的编码格式来查找编码器。我们选择的是H264编码器,因此编码器选择为AV_CODEC_ID_H264。

avcodec_open2():打开上一个函数所查找的编码器。

avformat_write_header():带文件头的封装格式需要调用这个函数写文件头,主要作用是将指定格式文件的一些相关信息写入到文件当中。

avcodec_encode_video2():编码一帧视频。将从V4L2采集到的AVFrame(存储YUV像素数据)编码为AVPacket(存储H.264等格式的码流数据)。

av_write_frame():将编码后的数据写入发送文件。

flush_encoder():用于输出编码器中剩余的AVPacket。

av_write_trailer():写文件尾。

调用read_and_encode_frame()函数,将从V4L2模块取得的YUV数据保存在Camera结构体内y420p_buffer指针指向的内存中,此时可以调用智能跟踪算法对目标进行跟踪。接下来将获取的YUV数据送入FFmepg函数avcodec_encode_video2()中,会将编码好H264数据Nalu的结构体保存在cam->encode.pkt中,实现编码的核心代码为:

int encode(Camera*cam)

{

int  got_output,ret;

unsigned  char *yuv420p;

int  y_size;

cam->encode.pkt.data  = NULL;/cam->encode.pkt.size = 0;

//Read  raw YUV data

read_and_encode_frame(cam);

y_size  = cam->encode.pCodecCtx->width * cam->encode.pCodecCtx->height;

yuv420p=cam->y420p_buffer;

cam->encode.pFrame->data[0]=yuv420p;

cam->encode.pFrame->data[1]=yuv420p+y_size;

cam->encode.pFrame->data[2]=yuv420p+5*y_size/4;

cam->encode.pFrame->pts  = cam->encode.framecnt;

//  encode the image

ret  = avcodec_encode_video2(cam->encode.pCodecCtx, &cam->encode.pkt,  cam->encode.pFrame, &got_output);

free(cam->y420p_buffer);

if  (ret < 0)

{

printf("Error  encoding frame\n");

return  -1;

}

return  0;

}

此时可以获取已经编码好的H264数据,为了适用与RTMP传输,每一帧YUV数据编译为H264数据使用了单线程,所以得到的每一个Nalu含有完整的一副图像,便与接收与显示。

至此,完成了支持轻量级RTMP多媒体视频服务器的采集编码端的编写。

上一篇下一篇

猜你喜欢

热点阅读