RTSP播放器高RTSP兼容推流网页无插件流媒体播放器EasyPlayer-RTSP关于MP4的封装调用流程介绍
EasyPlayer-RTSP播放器是一套RTSP专用的播放器,包括有:Windows(支持IE插件,npapi插件)、Android、iOS三个平台,是区别于市面上大部分的通用播放器,EasyPlayer-RTSP更加精炼、更加专注,具备低延时和高RTSP协议兼容性,编码数据解析等方面,都有非常大的优势。
EasyPlayer-RTSP-Win中录像采用GPAC的MP4Box库来封装MP4,下面我将简单介绍MP4的封装调用流程和需要注意的点;
一、GPAC库的编译,GPAC是跨平台的库,windows和linux都能很方便多编译,再次不做过多赘述,大家可去GPAC官网或者Github上下载;
二、创建MP4
bool EasyMP4Writer::CreateMP4File(char*filename,int flag)
{SaveFile();m_audiostartimestamp=-1;m_videostartimestamp=-1;if(filename==NULL){char filename2[256]={0};sprintf(filename2,"%d-gpac%d.mp4",time(NULL),rand());p_file=gf_isom_open(filename2,GF_ISOM_OPEN_WRITE,NULL);//打开文件}elsep_file=gf_isom_open(filename,GF_ISOM_OPEN_WRITE,NULL);//打开文件if (p_file==NULL){return false;}gf_isom_set_brand_info(p_file,GF_ISOM_BRAND_MP42,0);//if(flag&ZOUTFILE_FLAG_VIDEO)//{// m_videtrackid=gf_isom_new_track(p_file,0,GF_ISOM_MEDIA_VISUAL,1000);// gf_isom_set_track_enabled(p_file,m_videtrackid,1);//}//if(flag&ZOUTFILE_FLAG_AUDIO)//{// m_audiotrackid=gf_isom_new_track(p_file,0,GF_ISOM_MEDIA_AUDIO,1000);// gf_isom_set_track_enabled(p_file,m_audiotrackid,1);//}m_nCreateFileFlag = flag;return true;
}
创建MP4很简单,调用gf_isom_open函数就能轻松搞定,gf_isom_set_brand_info函数设置当前写MP4的版本为MP4V2;值得注意的地方是:
1>. 创建文件之前需要对所有的参数进行初始化,以及如果文件正在写入则需要将其关闭,这个操作主要是32位程序写的MP4文件大于4G可能出现不能播放的问题,为了方便写MP4文件进行分片,这个将在系列文章后续中进行讲解;
2>. 大家可以看到上段代码有屏蔽了部分代码flag&ZOUTFILE_FLAG_VIDEO和flag&ZOUTFILE_FLAG_AUDIO的判断,这两段代码是用来在MP4文件中创建音频轨和视频轨(默认各只创建一个),请注意:如果这里已经创建了音频和视频轨,然而后续的写入过程中如果只写音频或者视频的话,某些播放器可能是播不出来的(比如windows自带的播放器),所以,如果只写音频的话只需要创建音频轨就可以了,视频同理。
三、写入视频H264的SPS和PPS头信息
bool EasyMP4Writer::WriteH264SPSandPPS(unsigned char*sps,int spslen,unsigned char*pps,int ppslen,int width,int height)
{ if (m_nCreateFileFlag&ZOUTFILE_FLAG_VIDEO){m_videtrackid = gf_isom_new_track(p_file, 0, GF_ISOM_MEDIA_VISUAL, 1000);gf_isom_set_track_enabled(p_file, m_videtrackid, 1);}else{return false;}p_videosample=gf_isom_sample_new();p_videosample->data=(char*)malloc(1024*1024);p_config=gf_odf_avc_cfg_new(); gf_isom_avc_config_new(p_file,m_videtrackid,p_config,NULL,NULL,&i_videodescidx);gf_isom_set_visual_info(p_file,m_videtrackid,i_videodescidx,width,height);GF_AVCConfigSlot m_slotsps={0};GF_AVCConfigSlot m_slotpps={0};p_config->configurationVersion = 1;p_config->AVCProfileIndication = sps[1];p_config->profile_compatibility = sps[2];p_config->AVCLevelIndication = sps[3];m_slotsps.size=spslen;m_slotsps.data=(char*)malloc(spslen);memcpy(m_slotsps.data,sps,spslen); gf_list_add(p_config->sequenceParameterSets,&m_slotsps);m_slotpps.size=ppslen;m_slotpps.data=(char*)malloc(ppslen);memcpy(m_slotpps.data,pps,ppslen);gf_list_add(p_config->pictureParameterSets,&m_slotpps);gf_isom_avc_config_update(p_file,m_videtrackid,1,p_config);free(m_slotsps.data);free(m_slotpps.data);return true;
}
首先,通过gf_odf_avc_cfg_new()创建一个设置AVC信息的配置结构p_config,然后对结构中指定的信息,如:长,宽,SPS和PPS等关键参数写入配置结构,调用gf_isom_avc_config_update函数写入参数信息;当然这里只是H264格式的参数设置,像其他的格式比如H265的设置也类似,这将在后续系列中进行讲解;
四、写入音频AAC头信息
//写入AAC信息
bool EasyMP4Writer::WriteAACInfo(unsigned char*info,int len, int nSampleRate, int nChannel, int nBitsPerSample)
{if (m_nCreateFileFlag&ZOUTFILE_FLAG_AUDIO){m_audiotrackid = gf_isom_new_track(p_file, 0, GF_ISOM_MEDIA_AUDIO, 1000);gf_isom_set_track_enabled(p_file, m_audiotrackid, 1);}else{return false;}p_audiosample=gf_isom_sample_new();p_audiosample->data=(char*)malloc(1024*10);GF_ESD*esd= gf_odf_desc_esd_new(0);esd->ESID=gf_isom_get_track_id(p_file,m_audiotrackid);esd->OCRESID=gf_isom_get_track_id(p_file,m_audiotrackid);esd->decoderConfig->streamType=0x05;esd->decoderConfig->objectTypeIndication=0x40;//0x40;esd->slConfig->timestampResolution=1000;//1000;//时间单元 esd->decoderConfig->decoderSpecificInfo=(GF_DefaultDescriptor*)gf_odf_desc_new(GF_ODF_DSI_TAG);esd->decoderConfig->decoderSpecificInfo->data=(char*)malloc(len);memcpy(esd->decoderConfig->decoderSpecificInfo->data,info,len);esd->decoderConfig->decoderSpecificInfo->dataLength=len;GF_Err gferr=gf_isom_new_mpeg4_description(p_file, m_audiotrackid, esd, NULL, NULL, &i_audiodescidx);if (gferr!=0){
// TRACE("mpeg4_description:%d\n",gferr);}gferr=gf_isom_set_audio_info(p_file,m_audiotrackid,i_audiodescidx, nSampleRate,nChannel, nBitsPerSample);//44100 2 16if (gferr!=0){
// TRACE("gf_isom_set_audio:%d\n",gferr);}free(esd->decoderConfig->decoderSpecificInfo->data);return true;
}
调几个 API就搞定了,一如既往的简单–!,这里说一下一些关键参数的配置:
1> esd->decoderConfig->streamType=0x05,这里的0x05标示为AAC,当然还指出其他的类型,如MP3,AC3等等,具体可查询MP4BOX相关文档获取;
2> 函数出入的头两个参数大家看起来有点费解,这里表示的是音频解码参数组合的一个串,具体格式解析如下:(这个本来想单独开一篇博客来专门阐述的,但是鉴于没多少内容就在这里一并表述出来)
看下面代码段:
// 前五位为 AAC object types LOW 2// 接着4位为 码率index 16000 8// 采样标志标准:// static unsigned long tnsSupportedSamplingRates[13] = //音频采样率标准(标志),下标为写入标志// { 96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000,0 };// 接着4位为 channels 个数 2// 最后3位用0补齐// 应打印出的正确2进制形式为 00010 | 1000 | 0010 | 000// 2 8 2// BYTE ubDecInfoBuff[] = {0x12,0x10};//00010 0100 0010 000//音频采样率标准(标志),下标为写入标志unsigned long tnsSupportedSamplingRates[13] = { 96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000,0 };int nI = 0;for ( nI = 0; nI<13; nI++){if (tnsSupportedSamplingRates[nI] == sample_rate ){break;}}unsigned char ucDecInfoBuff[2] = {0x12,0x10};//unsigned short nDecInfo = (1<<12) | (nI << 7) | (channels<<3);int nSize = sizeof(unsigned short);memcpy(ucDecInfoBuff, &nDecInfo, nSize);SWAP(ucDecInfoBuff[0], ucDecInfoBuff[1]);int unBuffSize = sizeof(ucDecInfoBuff)*sizeof(unsigned char);
大家看懂了吧,比如现在有个表示解码信息的串为 00010 | 0100 | 0010 | 000 ,那么它则表示为AAC-LC 44100采样率 双声道音频,是不是很好理解呢!!!
五、解析H264帧写入MP4
下面用文字描述,分三步走:
1> 解析H264 nal头,获取SPS和PPS, 因为我们已经通过设置函数设置了SPS和PPS等解码关键信息,所以我们写入文件时,H264帧将转换为AVC格式,什么意思,就是说将以00000001以及000001开头的NAL单元转换为以该NAL单元的长度来填满该四个字节(注意:所有的H264帧中的0x00000001和0x000001都要替换成NAL的长度,否则未替换的部分解码会花屏),默认三个字节的000001也用四个字节补齐,这主要是见于一帧多NAL的情况,这里有疑问我将在后续系列文章中讲解;
2> 写入SPS和PPS头;
3> 写入以NAL长度为头四个字节的AVC帧,具体实现如下:
//写入一帧,前四字节为该帧NAL长度
bool EasyMP4Writer::WriteVideoFrame(unsigned char*data,int len,bool keyframe,long timestamp)
{ if (!p_videosample){return false;}if (m_videostartimestamp==-1&&keyframe){m_videostartimestamp=timestamp;}if (m_videostartimestamp!=-1){p_videosample->IsRAP=keyframe;p_videosample->dataLength=len;memcpy(p_videosample->data,data,len);p_videosample->DTS=timestamp-m_videostartimestamp;p_videosample->CTS_Offset=0; GF_Err gferr=gf_isom_add_sample(p_file,m_videtrackid,i_videodescidx,p_videosample); if (gferr==-1){p_videosample->DTS=timestamp-m_videostartimestamp+15;gf_isom_add_sample(p_file,m_videtrackid,i_videodescidx,p_videosample);}}return true;
}
六、AAC写入MP4(是否带ADTS头)
同写视频类似,写音频同样要先写如音频解码参数,上文已经分析过如何写解码参数,这里只需把解码参数信息组织成串,通过WriteAACInfo()函数写入即可。
写音频数据,实现和视频一样,调用gf_isom_add_sample函数即可;
需要注意:因为我们已经写入了音频解码信息,那么如果AAC数据中带有ADTS头,则需要去掉则7个字节的头,否则可能部分播放器不能正常播放,ADTS头以 0xFFF 开始;
七、写入MP4封装头,保存文件
保存文件,释放缓存和系统资源:
//保存文件
bool EasyMP4Writer::SaveFile()
{if (m_psps){delete m_psps;m_psps = NULL;}if (m_ppps){delete m_ppps;m_ppps = NULL;}m_spslen=0;m_ppslen=0;if (m_pvps){delete m_pvps;m_pvps = NULL;}m_vpslen = 0;m_audiostartimestamp=-1;m_videostartimestamp=-1;if (p_file){gf_isom_close(p_file);p_file=NULL;}if(p_config){// delete p_config->pictureParameterSets;p_config->pictureParameterSets=NULL;// delete p_config->sequenceParameterSets;p_config->sequenceParameterSets=NULL;gf_odf_avc_cfg_del(p_config);p_config=NULL;}if (p_hevc_config){gf_odf_hevc_cfg_del(p_hevc_config);p_hevc_config = NULL;}if( p_audiosample){if( p_audiosample->data){free(p_audiosample->data);p_audiosample->data=NULL;}gf_isom_sample_del(&p_audiosample);p_audiosample=NULL;}if( p_videosample){if( p_videosample->data){free(p_videosample->data);p_videosample->data=NULL;}gf_isom_sample_del(&p_videosample);p_audiosample=NULL;}m_bwriteaudioinfo = false;m_bwritevideoinfo = false;return true;
}
RTSP播放器高RTSP兼容推流网页无插件流媒体播放器EasyPlayer-RTSP关于MP4的封装调用流程介绍相关推荐
- 多功能流媒体播放器实现网页无插件直播之EasyPlayer.js如何实现播放完自动循环播放
EasyPlayer-Android播放器是一款可针对RTSP.RTMP.RTSP&RTMP协议进行过优化的流媒体播放器,其中我们引以为傲的两个技术优势就是起播速度快和播放延迟低.最近我们遇到 ...
- 海康大华等摄像头RTSP低延迟(1秒以内)网页无插件播放解决方案
简介 监控摄像头网页无插件播放解决方案虽然很多,但是或多或少会有一定的延迟,其中网上使用最多的是RTSP转RTMP推流的方式,这种延迟一般十秒左右,优化的好的话能达到五秒,但是依旧算不上实时.本文提供 ...
- RTSP安防网络摄像头/海康大华硬盘录像机/NVR网页无插件低延时播放流媒体服务器EasyNVR页面显示网络请求失败问题
进入移动互联网时代以来,企业微信公众号已成为除官网以外非常重要的宣传渠道,当3.2亿直播用户与9亿微信用户的势能累加,在微信上开启直播已成为越来越多企业的必然选择. 青犀团队研发的EasyNVR核心在 ...
- html5 无插件视频播放器,多功能流媒体播放器网页无插件直播EasyPlayer.js如何实现播放完自动循环播放...
原标题:多功能流媒体播放器网页无插件直播EasyPlayer.js如何实现播放完自动循环播放 EasyPlayer-Android播放器是一款可针对RTSP.RTMP.RTSP&RTMP协议进 ...
- 网页无插件视频流媒体播放器EasyPlayer.JS切换多清晰度码流播放报错,该如何调试?
EasyPlayer是一款流媒体播放器系列项目,支持RTSP.RTMP.HTTP.HLS.UDP.RTP.File等多种流媒体协议播放.支持本地文件播放,支持本地抓拍.本地录像.播放旋转.多屏播放.倍 ...
- 流媒体服务器+终端(android,ios,web),如何从海康平台上拉流接入RTSP安防网络摄像头/海康大华硬盘录像机网页无插件直播流媒体服务器EasyNVR?...
背景需求 随着雪亮工程.明厨亮灶.手机看店.智慧幼儿园监控等行业开始将传统的安防摄像头进行互联网.微信直播,我们知道摄像头直播的春天了.将安防摄像头或NVR上的视频流转成互联网直播常用的RTMP.HT ...
- 新版RTSP协议网络摄像头网页无插件直播平台EasyNVR如何自定义通道的背景音乐?
EasyNVR网页无插件直播平台经过多次的修正和改良,已经成为一套成熟的流媒体视频云服务平台,能够满足安防.智慧城市.教育等不同场景的应用需求. 目前,最新版本的EasyNVR支持自定义背景音乐,用户 ...
- 视频在html不能播放器,网页无插件直播H265编码视频播放器EasyPlayer网页播放器不能播放怎么处理?...
原标题:网页无插件直播H265编码视频播放器EasyPlayer网页播放器不能播放怎么处理? EasyPlayer播放器系列项目提供了非常简单易用的SDK及API接口,用户通过API调用就可以非常快速 ...
- 安防RTSP无插件直播方案及RTSP配置规则
LiveNVR搭建无插件直播方案时,采用行业标准的通用协议RTSP/Onvif接入摄像机IPC摄像机 / NVR硬盘录像机设备:Onvif是摄像机的发现与控制管理协议,Onvif用到的流媒体协议也是R ...
最新文章
- if null 锁 java_史上最全 Java 中各种锁的介绍
- different application signatures解决方法
- WPF 提供了以下关键帧动画类[msdn]
- 理解图像中卷积操作的含义
- Visual Studio 2008 和 .NET Framework 3.5 Service Pack 1 Beta 发布
- cisco 两个设备之间测试吞吐量的一个方法
- stm8s003程序跑飞_微信小程序只玩跳一跳?OUT啦!带你玩更好玩的微信小游戏!...
- jeesite导出Excel Minimum column number is 0
- 诗与远方:无题(二十八)- 曾经写给妹子的一首诗
- hdu 4027 Can you answer these queries?
- 苹果mac绘图软件:AutoCAD
- 吴恩达机器学习视频学习笔记(3)
- 社交APP软件开发流程解析
- 完整卸载SQL Server2008
- 几个国内的 apple 相关社区
- 第六讲 幂级数的收敛半径和收敛域
- 如何计算变量或数据类型所占内存空间的大小
- 基于 RTS 超低延时直播优化强互动场景体验
- 教师职业道德与专业发展
- ROS学习——rotors仿真下载与运行
热门文章
- windows10系统修改c盘Users目录中的中文名称
- 山东理工大学ACM平台题答案 2561 九九乘法表
- 《On Java》介绍
- 基于数字电路交通灯信号灯控制系统设计-基于单片机病房温度监测与呼叫系统设计-基于STM32的无线蓝牙心电监护仪系统设计-基于STM32的智能蓝牙温控风扇控制设计-基于STM32的智能温室控制系统设计
- Chrome的隐身模式
- cos三次方积分_cosx的四次方如何积分?
- 如何将此电脑放到桌面上(windows10版本)
- SQLServer 自定义函数 日期计算月初/月末/年初/年末/季初/季末
- Unity-tweak-tool插件
- 支持向量机 实战电信运营商 -客户流失预警