LivePush视频直播推送中对H264帧类型判断

    xiaoxiao2021-04-16  31

    H264

    H264在网络传输的是NALU,NALU的结构是:NAL头+RBSP,实际传输中的数据流如图所示:

    其中NAL头占一个字节,其低5个bit位表示NAL type,具体如下表:

    NAL typeNAL类型0未使用1非IDR的片2片数据A分区3片数据B分区4片数据C分区5IDR图像的片6补充增强信息单元(SEI)7序列参数集(SPS)8图像参数集(PPS)9分界符10序列结束11码流结束12填充13…23保留24…31不保留

    RBSP 为原始字节序列载荷。

    NAL type为5,则此帧为I帧即关键帧,type为1时为非关键帧(P帧…)。 在实际的H264数据帧中,往往帧NAL type前面带有00 00 00 01 或 00 00 01分隔符,一般来说编码器编出的首帧数据为PPS与SPS,接着为I帧,然后是P帧…

    LivePush 视频流推送#

    LivePush通过调用摄像机SDK、拉取RTSP流、读mp4文件等方式获取到H264视频流及音频视频流到本地作为视频源,再以RTSP、RTMP方式推送给流媒体服务器。它们都是支持Windows、Linux、Android、iOS、ARM等全平台的视频流推送程序。 下面介绍下它们在获取到视频流到本地后如何区分I帧和P帧等,然后推送的:

    //这段代码是从文件中读取h264数据,然后推送给服务器 unsigned char *ptr=new unsigned char [sample_size]; fread(ptr, sample_size, 1, g_fin); //写一帧数据 --- 可以直接进行网络推送 //fwrite(ptr, sample_size, 1, fout); EASY_AV_Frame avFrame; memset(&avFrame, 0x00, sizeof(EASY_AV_Frame)); /* *ptr的前4字节是帧分分割符00 00 00 01 , 第5个字节是NAL type */ unsigned char naltype = ( (unsigned char)ptr[4] & 0x1F); avFrame.pBuffer = (unsigned char*)ptr; avFrame.u32AVFrameLen = sample_size; avFrame.u32VFrameType = (naltype==0x05)?EASY_SDK_VIDEO_FRAME_I:EASY_SDK_VIDEO_FRAME_P; avFrame.u32AVFrameFlag = EASY_SDK_VIDEO_FRAME_FLAG; avFrame.u32TimestampSec = lTimeStamp/1000000; avFrame.u32TimestampUsec = (lTimeStamp00000);

    如果视频源不是文件,而是IPCamera 或者RTSP流等,在他们的视频流回调中可能已经告知当前帧是I帧还是P帧,就省去了判断NAL type的步骤。

    HI_S32 NETSDK_APICALL OnStreamCallback(HI_U32 u32Handle,/* 句柄 */ HI_U32 u32DataType, /* 数据类型,视频或音频数据或音视频复合数据 */ HI_U8* pu8Buffer, /* 数据包含帧头 */ HI_U32 u32Length, /* 数据长度 */ HI_VOID* pUserData /* 用户数据*/ ) { HI_S_AVFrame* pstruAV = HI_NULL; HI_S_SysHeader* pstruSys = HI_NULL; if (u32DataType == HI_NET_DEV_AV_DATA) { pstruAV = (HI_S_AVFrame*)pu8Buffer; if (pstruAV->u32AVFrameFlag == HI_NET_DEV_VIDEO_FRAME_FLAG) { if(fPusherHandle == 0 ) return 0; if(pstruAV->u32AVFrameLen > 0) { unsigned char* pbuf = (unsigned char*)(pu8Buffer+sizeof(HI_S_AVFrame)); EASY_AV_Frame avFrame; memset(&avFrame, 0x00, sizeof(EASY_AV_Frame)); avFrame.u32AVFrameLen = pstruAV->u32AVFrameLen; avFrame.pBuffer = (unsigned char*)pbuf; avFrame.u32VFrameType = (pstruAV->u32VFrameType==HI_NET_DEV_VIDEO_FRAME_I)?EASY_SDK_VIDEO_FRAME_I:EASY_SDK_VIDEO_FRAME_P; avFrame.u32AVFrameFlag = EASY_SDK_VIDEO_FRAME_FLAG; avFrame.u32TimestampSec = pstruAV->u32AVFramePTS/1000; avFrame.u32TimestampUsec = (pstruAV->u32AVFramePTS00)*1000; EasyPusher_PushFrame(fPusherHandle, &avFrame); } } else if (pstruAV->u32AVFrameFlag == HI_NET_DEV_AUDIO_FRAME_FLAG) { if(fPusherHandle == 0 ) return 0; if(pstruAV->u32AVFrameLen > 0) { //不同IPCamera,这里数据头不一样,需要根据各自的SDK跳过对应的大小。有些可能没有自定义数据 unsigned char* pbuf = (unsigned char*)(pu8Buffer+sizeof(HI_S_AVFrame)); EASY_AV_Frame avFrame; memset(&avFrame, 0x00, sizeof(EASY_AV_Frame)); avFrame.u32AVFrameLen = pstruAV->u32AVFrameLen-4;//去掉厂家自定义的4字节头 avFrame.pBuffer = (unsigned char*)pbuf+4; avFrame.u32AVFrameFlag = EASY_SDK_AUDIO_FRAME_FLAG; avFrame.u32TimestampSec = pstruAV->u32AVFramePTS/1000; avFrame.u32TimestampUsec = (pstruAV->u32AVFramePTS00)*1000; EasyPusher_PushFrame(fPusherHandle, &avFrame); } } } else if (u32DataType == HI_NET_DEV_SYS_DATA) { pstruSys = (HI_S_SysHeader*)pu8Buffer; printf("Video W:%u H:%u Audio: %u \n", pstruSys->struVHeader.u32Width, pstruSys->struVHeader.u32Height, pstruSys->struAHeader.u32Format); } return HI_SUCCESS; }

    获取更多信息

    邮件:support@liveqing.com

    技术交流QQ群:615081503

    咨询电话:15156896292

    LiveQing视频流媒体无插件直播方案:www.liveqing.com

    Copyright © LiveQing Team 2016-2019

    转载请注明原文地址: https://ju.6miu.com/read-673150.html

    最新回复(0)