Easypusher接口推送RTP数据

最近在整合asterisk系统的视频通话录像功能,开始使用mp4v2库直接在asterisk系统中进行mp4视频文件的生成,测试发现性能上存在瓶颈,只能做到50路(双向即100mp4文件)左右的并发通话的mp4文件生成,初步分析问题主要在写文件上,鉴于此,希望能把RTP流送出到别的服务中进行录制。在网上查找了相关的流媒体服务,发现easydarwin比较适合我们当前的应用场景,准备使用其作为我们的流媒体服务器使用,把对接过程所遇到的问题进行记录,希望对有这方面应用的XDJM有一定的帮助。

 

一、环境说明:

1、EasyDarwin版本:Server: EasyDarwin/7.0.5 (Build/16.0518; Platform/Win32; Release/EasyDarwin; State/Development; )

 

下载地址:https://github.com/EasyDarwin/EasyDarwin/releases

2、Easypusher静态库版本:v1.2.16.1105

静态库下载地址:https://github.com/EasyDarwin/EasyPusher

3、Asterisk版本:Asterisk 1.8.20.1 built   (自行到官网下载一个能用的版本应该都行)

4、

 

二、源码:

 

isActivated = EasyPusher_Activate(KEY);/* 目前用到.a库的话,需要临时授权 */

switch(isActivated)

{

case EASY_ACTIVATE_INVALID_KEY:

ast_log(LOG_DEBUG, "KEY is EASY_ACTIVATE_INVALID_KEY!\n");

break;

case EASY_ACTIVATE_TIME_ERR:

ast_log(LOG_DEBUG, "KEY is EASY_ACTIVATE_TIME_ERR!\n");

break;

case EASY_ACTIVATE_PROCESS_NAME_LEN_ERR:

ast_log(LOG_DEBUG, "KEY is EASY_ACTIVATE_PROCESS_NAME_LEN_ERR!\n");

break;

case EASY_ACTIVATE_PROCESS_NAME_ERR:

ast_log(LOG_DEBUG, "KEY is EASY_ACTIVATE_PROCESS_NAME_ERR!\n");

break;

case EASY_ACTIVATE_VALIDITY_PERIOD_ERR:

ast_log(LOG_DEBUG, "KEY is EASY_ACTIVATE_VALIDITY_PERIOD_ERR!\n");

break;

case EASY_ACTIVATE_SUCCESS:

ast_log(LOG_DEBUG, "KEY is EASY_ACTIVATE_SUCCESS!\n");

break;

}

 

if(EASY_ACTIVATE_SUCCESS != isActivated)

{

ast_log(LOG_ERROR, "EasyPusher_Activate : NOT EASY_ACTIVATE_SUCCESS\n");

//return -1;

}

 

 memset(&fSourceMediaInfo, 0x00, sizeof(EASY_MEDIA_INFO_T));

fSourceMediaInfo.u32VideoCodec = EASY_SDK_VIDEO_CODEC_H264;// fSourceMediaInfo.u32VideoFps = 25; //

 

/*711语音处理*/

fSourceMediaInfo.u32AudioCodec = 0x10007;//EASY_SDK_AUDIO_CODEC_G711A;

fSourceMediaInfo.u32AudioSamplerate = 8000;

fSourceMediaInfo.u32AudioChannel = 1;

 

fPusherHandle = EasyPusher_Create();

fPusherBuff = malloc(2048*1024);

If (NULL == fPusherBuff )

    Return -1;

memset(fPusherBuff, 0, 2048*1024);

EasyPusher_SetEventCallback(fPusherHandle, __EasyPusher_Callback, 0, NULL);

EasyPusher_StartStream(fPusherHandle, ConfigIP, atoi(ConfigPort), ConfigName, "admin", "admin", &fSourceMediaInfo, 2048, 0);//2M缓冲区

ast_log(LOG_WARNING, "*** live streaming url:rtsp://%s:%d/%s ***\n", ConfigIP, atoi(ConfigPort), ConfigName);

bfile=fopen("/Data/h264test.264", "at+");/*调试用,写h264裸文件*/

 

 

{

now = ast_tvnow();

if( (f->frametype == AST_FRAME_VOICE)  && spsflag )// spsflag: 先写入视频数据

{

EASY_AV_Frame  avoiceFrame;

if(f->subclass.codec & AST_FORMAT_ALAW)//  例子里只处理ALAW语音,实际看接口,还支持ULAWG726AAC

{

//ast_log(LOG_WARNING, "AST_FORMAT_ALAW    f->datalen[%d]\n", f->datalen);

memset(&avoiceFrame, 0x00, sizeof(EASY_AV_Frame));

avoiceFrame.u32AVFrameLen =  f->datalen ;

avoiceFrame.pBuffer =AST_FRAME_GET_BUFFER(f) ;/* RTP包中的771裸数据,即RTP包中的PAYLOAD数据 */

avoiceFrame.u32AVFrameFlag = EASY_SDK_AUDIO_FRAME_FLAG;

avoiceFrame.u32TimestampSec =now.tv_sec;

avoiceFrame.u32TimestampUsec = now.tv_usec;

EasyPusher_PushFrame(fPusherHandle, &avoiceFrame);

}

}

else if (f->frametype == AST_FRAME_VIDEO) //写入视频数据

{

if (f->subclass.codec & AST_FORMAT_H264)

{

EASY_AV_Frame   avideoFrame;

unsigned char *frame = NULL;

unsigned char ttype ;

unsigned char h264_hdr[4] = {0};

 

frame = AST_FRAME_GET_BUFFER(f);/* RTP包中的h264裸数据,即RTP包中的PAYLOAD数据 */

ttype = (unsigned char)frame[0] & 0x1F;

memset(&avideoFrame, 0x00, sizeof(EASY_AV_Frame));

avideoFrame.u32TimestampSec = now.tv_sec;

avideoFrame.u32TimestampUsec = now.tv_usec;

 

h264_hdr[3] |= 0x1;

  /* 只有是SPSP帧才去调用API发送;否则会出现easydarwin保存成文件后,播放不出来的问题(直播不存在问题),具体原因不明确 */

if ((0x7 == ttype) || (0x1 == ttype))

{

spsflag += 1;

if (spsflag >1)

{

            fwrite(h264_hdr, 4, 1, bfile);

            fwrite(AST_FRAME_GET_BUFFER(f), 1, f->datalen, bfile);

     ttype = (unsigned char)fPusherBuff[4] & 0x1F;

            avideoFrame.u32VFrameType = (ttype==0x07)?EASY_SDK_VIDEO_FRAME_I:EASY_SDK_VIDEO_FRAME_P;

            avideoFrame.u32AVFrameFlag = EASY_SDK_VIDEO_FRAME_FLAG;

            avideoFrame.u32AVFrameLen   =   fPusherBuffOffset;

            avideoFrame.pBuffer = fPusherBuff;

     spsflag = 1;

     EasyPusher_PushFrame(fPusherHandle, &avideoFrame);

 

     fPusherBuffOffset = 0;

     memset(fPusherBuff, 0, 2048*1024);

 

 

     memcpy(fPusherBuff+fPusherBuffOffset, h264_hdr, 4);

     fPusherBuffOffset += 4;

     memcpy(fPusherBuff+fPusherBuffOffset , AST_FRAME_GET_BUFFER(f), f->datalen);

     fPusherBuffOffset += f->datalen;

 

}

else

{

/*调试用,写h264裸文件*/

            fwrite(h264_hdr, 4, 1, bfile);

            fwrite(AST_FRAME_GET_BUFFER(f), 1, f->datalen, bfile);

     memcpy(fPusherBuff+fPusherBuffOffset, h264_hdr, 4);

     fPusherBuffOffset += 4;

     memcpy(fPusherBuff+fPusherBuffOffset , AST_FRAME_GET_BUFFER(f), f->datalen);

     fPusherBuffOffset += f->datalen;

}

}

else

{

            fwrite(h264_hdr, 4, 1, bfile);/*调试用,写h264裸文件*/

            fwrite(AST_FRAME_GET_BUFFER(f), 1, f->datalen, bfile);

     memcpy(fPusherBuff+fPusherBuffOffset, h264_hdr, 4);

     fPusherBuffOffset += 4;

     memcpy(fPusherBuff+fPusherBuffOffset , AST_FRAME_GET_BUFFER(f), f->datalen);

     fPusherBuffOffset += f->datalen;

}

 

}

}

}

 

三、参考:

1、利用EasyRTSPClient工具检查摄像机RTSP流不能播放原因以及排查音视频数据无法播放问题:http://blog.csdn.net/xiejiashu/article/details/53105103

2、H264裸数据推送参考:https://github.com/EasyDarwin/EasyPusher  解压后的EasyPusher_File目录

 

四、感谢:

非常感谢在调测试过程中,Babosa大神给予的指点,具体问题可以在EasyDarwin开源流媒体服务器QQ群中提出:496258327()

 

五、后续:

后续会针对并发性能做个测试,有新进展的话贴出分享受给大家

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Java中推送RTP流可以使用JMF(Java Media Framework)和FFmpeg等库。 JMF是一个Java媒体框架,提供了一组API,用于实现音频和视频流的捕捉、编码、解码、播放等功能。JMF支持RTP/RTCP协议,可以使用RTPManager类来推送RTP流。下面是一个使用JMF推送RTP流的示例代码: ``` import javax.media.*; import javax.media.protocol.*; import javax.media.rtp.*; import javax.media.rtp.event.*; import javax.media.rtp.rtcp.*; public class RTPSender { public static void main(String[] args) throws Exception { // 创建一个RTPManager实例 RTPManager rtpManager = RTPManager.newInstance(); // 创建一个RTP发送端 SessionAddress localAddress = new SessionAddress(); rtpManager.initialize(localAddress); rtpManager.addSessionListener(new SessionAdapter() { public void sessionCreated(SessionEvent event) { System.out.println("RTP session created: " + event.getSession().getSessionAddress()); } }); // 创建一个数据源 DataSource dataSource = Manager.createDataSource(new MediaLocator("file://audio.wav")); // 创建一个RTP数据传输器 SendStream sendStream = rtpManager.createSendStream(dataSource, 0); // 开始发送RTP流 sendStream.start(); System.out.println("RTP stream started."); // 等待RTP流结束 while (true) { Thread.sleep(1000); } } } ``` 上面的示例代码使用JMF创建了一个RTPManager实例,然后创建了一个RTP发送端,再创建一个数据源和一个RTP数据传输器,最后开始发送RTP流。需要注意的是,这里的数据源可以是音频或视频文件、摄像头、屏幕捕捉等。 除了JMF,还可以使用FFmpeg库来推送RTP流。FFmpeg是一个跨平台的开源多媒体框架,支持各种音视频编码格式和协议,包括RTP/RTCP协议。下面是一个使用FFmpeg推送RTP流的示例命令: ``` ffmpeg -re -i input.mp4 -vcodec copy -an -f rtp rtp://127.0.0.1:5004 ``` 上面的命令使用FFmpeg推送了一个MP4视频文件的RTP流,将其发送到IP地址为127.0.0.1、端口号为5004的目的地。在Java中,可以使用ProcessBuilder类来执行FFmpeg命令,从而实现推送RTP流的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值