1、ORTP庫安裝編譯
注意;要增加H.264的payload支援。
在src/avprofile.c中357行添加:
rtp_profile_set_payload(profile,96,&payload_type_h264);//這個96是h.264幀頭的一個資訊
配置和編譯、安裝
(1)進入ortp目錄執行./autogen.sh
(2)錯誤1:./autogen.sh: line 44: libtoolize: command not found
解決:sudo apt-get install libtool* 注意安裝的時候要保證虛拟機聯網
(2)錯誤2:libtoolize: error: Please install GNU M4, or ‘export M4=/path/to/gnu/m4’.
解決:sudo apt-get install m4
(3)錯誤3:Automake - aclocal: command not found
解決:sudo apt-get install automake
(4)繼續執行./configure --prefix=/tmp/ortp --host=arm-hisiv300-linux
prefix 安裝目錄,,host 交叉編譯工具鍊的選擇
(5)make && make install
最後;到/tmp/ortp目錄下檢視移植好的庫和頭檔案,之後在使用的時候要包含ku檔案和頭檔案才能正确使用。
注意安裝的時候要保證虛拟機聯網
/etc/network/interface檔案
ifdown ens33
ifup ens33
2、合并到mmp的sample 編譯運作
修改代碼後
重新編譯sample
(1)複制ortp頭檔案 cp /tmp/ortp/include/ortp/ ./ -rf
(2)修改venc中Makefile,添加libortp的連結支援 -lortp -L路徑
$(TARGET):%:%.o $(COMM_OBJ)
$(CC) $(CFLAGS) -lpthread -lm -lortp -o [email protected] $^ $(MPI_LIBS) $(AUDIO_LIBA) $(SENSOR_LIBS) -L/tmp/ortp/lib
(3)venc下執行make
即可生成可執行程式,注意要把ortp庫的.h檔案和lib庫部署到開發闆,否則運作的時候會提示缺少庫的。
3、ORTP庫源碼學習
ORTP庫概覽
(1)庫本身沒有main,提供一堆功能函數,都在src目錄下
(2)庫的使用給了案例,有main,在src/tests目錄下,每個.c檔案就是一個案例
(3)相關資料結構和頭檔案在include/ortp目錄下
(4)ortp實作了rtp和rtcp協定,前者負責傳輸,後者rtcp是rtp庫的補充負責控制和同步協調。
3.1、以rtp_send.c為案例進行了解ORTP庫
第一步;主要完成對payload的注冊
av_profile_init(&av_profile)
rtp_profile_set_payload(profile,96,&payload type_h264);
第二步;初始化排程器
ortp_scheduler_init();
rtp_scheduler_new
ortp_malloc
rtp_scheduler_init 初始化互斥鎖、條件鎖,以及會話的初始化
rtp_scheduler_start
ortp_thread_create 互斥鎖保護,條件鎖等待建立線程
rtp_scheduler_schedule 線程函數、
第三步;建立session和設定會話屬性
rtp_session_new
ortp_malloc
rtp_session_init
rtp_session_set_profile 最終還是要設定會話的profile
rtp_session_enable_jitter_buffer 配置jitter防抖
rtp_session_set_ssrc 判斷設定ssrc同步源标志
第四步;讀取發送
rtp_session_send_with_ts
rtp_session_create_packet 給資料添加幀頭
rtp_session_sendm_with_ts 加了m表示完成格式;幀頭+内容
rtp_session_rtp_send
rtp_sendmsg or sendto
rtp_session_rtcp_process_send
rtp_sendmsg or sendto
細節部分;
ORTP中的排程器
排程器就是一個仲裁機構,也就是一段代碼,每隔一段時間執行一次決定排程誰,一般是線程或程序
ortp庫裡面的scheduler就是一個定時器,每隔多少時間執行一次、這裡面的排程實在幹嘛的?、ortp庫可以同時維持多路會話也就是多路通信,那麼就要需要排程運作保持分時複用
會話session ORTP庫的通信都是基于會話的,但是同時可以支援多個session同時進行,在代碼邏輯上
一個session最終都會展現到一段代碼一個資料結構就是結構體。
SSRC 同步源标志 這個可以用于會話通信的标志,當多路會話時用于可以根據資訊識别是那個會話
就是每個會話通信傳輸資訊的唯一識别碼、作用就是在多路會話的時候直接截取資訊可以根據ssrc知道是哪路會話的否則不知道。
jitter buffer防抖
jitter buffer技術是ip 音視訊通信裡相對比較進階的主題, jitter buffer子產品好壞通常是衡量一個voip用戶端/伺服器好壞的技術點之一,尤其是在網絡抖動比較嚴重,如3g,wifi環境,資料包的rtt值不均衡往往會導緻語音卡頓,丢字等現象,jitter buffer 子產品通過緩存一段資料包,把資料包重排,并均勻的送給播放端,一個好的jitter buffer實作通長是動态調整緩存大小的,在網絡延遲大,抖動嚴重時會動态增加緩存大小,在網絡恢複時動态減小緩存大小以減少端到端的播放延遲。
3.2、ORTP庫中create_and_bind函數
static ortp_socket_t create_and_bind
涉及到
struct addrinfo解釋
https://www.cnblogs.com/likui360/p/6128938.html
AF_XX 與PF_XX 位址族和協定族
setsockopt設定SO_REUSEADDR
https://blog.csdn.net/u010144805/article/details/78579528
3.3、RTP發送實驗源碼分析
首先要在common/sample_common_venc.c中添加ortp庫的初始化函數和發送函數;
然後再就是修改venc/sample_venc.c;mmp初始化編碼的步驟都不需要變,隻需要修改之前存放到檔案裡面去,現在是使用ortp包發送。
venc/sample_venc.c
//venc/sample_venc.c
HI_S32 SAMPLE_COMM_VENC_SaveH264(FILE* fpH264File, VENC_STREAM_S *pstStream)
{
HI_S32 i;
for (i = 0; i < pstStream->u32PackCount; i++)
{
//隻需要修改這裡
#if ORTP_ENABLE
rtpSend(pRtpSession,pstStream->pstPack[i].pu8Addr, pstStream->pstPack[i].u32Len);
#else
//檔案則需要考慮偏移量,而ortp庫則是網絡流每次放到原地即可
fwrite(pstStream->pstPack[i].pu8Addr+pstStream->pstPack[i].u32Offset,
pstStream->pstPack[i].u32Len-pstStream->pstPack[i].u32Offset, 1, fpH264File);
fflush(fpH264File);
#endif
}
sample_common_venc.c中
sample_common_venc.c中
//定義一個宏來管理。
#if ORTP_ENABLE
#include <ortp/ortp.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#define Y_PLOAD_TYPE 96 //H.264
#define MAX_RTP_PKT_LENGTH 1400
#define DefaultTimestampIncrement 3600 //(90000/25)
uint32_t g_userts=0;
RtpSession *pRtpSession = NULL;
#define LOCAL_HOST_IP "192.168.1.20"
/** 初始化
*
* 主要用于對ortp以及其它參數進行初始化
* @param: char * ipStr 目的端IP位址描述串
* @param: int port 目的端RTP監聽端口
* @return: RtpSession * 傳回指向RtpSession對象的指針,如果為NULL,則初始化失敗
* @note: 這個注意是從ortp-master\src\tests\rtpsend.c抄過來的
*/
RtpSession * rtpInit( char * ipStr, int port)
{
RtpSession *session;
char *ssrc;
printf("********oRTP for H.264 Init********\n");
ortp_init();
ortp_scheduler_init();
ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR);
session=rtp_session_new(RTP_SESSION_SENDONLY);
rtp_session_set_scheduling_mode(session,1);
rtp_session_set_blocking_mode(session,0);
//rtp_session_set_connected_mode(session,TRUE);
rtp_session_set_remote_addr(session,ipStr,port);//設定遠端IP和端口号 端口号就要兩邊一樣可以通信就行了
rtp_session_set_payload_type(session,Y_PLOAD_TYPE);
ssrc=getenv("SSRC");
if (ssrc!=NULL) {
printf("using SSRC=%i.\n",atoi(ssrc));
// 設定輸出流的SSRC。不做此步的話将會給個随機值
rtp_session_set_ssrc(session,atoi(ssrc));
}
return session;
}
/** 結束ortp的發送,釋放資源
*
* @param: RtpSession *session RTP會話對象的指針
* @return: 0表示成功
* @note:
*/
int rtpExit(RtpSession *session)
{
printf("********oRTP for H.264 Exit********\n");
g_userts = 0;
rtp_session_destroy(session);
ortp_exit();
ortp_global_stats_display();
return 0;
}
/** 發送rtp資料包
*
* 主要用于發送rtp資料包
* @param: RtpSession *session RTP會話對象的指針
* @param: const char *buffer 要發送的資料的緩沖區位址
* @param: int len 要發送的資料長度
* @return: int 實際發送的資料包數目
* @note: 如果要發送的資料包長度大于BYTES_PER_COUNT,本函數内部會進行分包處理
*/
int rtpSend(RtpSession *session, char *buffer, int len)
{
int sendBytes = 0;
int status;
uint32_t valid_len=len-4;
unsigned char NALU=buffer[4];
//分包發送,并且還涉及到一點H.264幀頭的資訊
//如果資料小于MAX_RTP_PKT_LENGTH位元組,直接發送:單一NAL單元模式
if(valid_len <= MAX_RTP_PKT_LENGTH)
{
sendBytes = rtp_session_send_with_ts(session,
&buffer[4], //注意從第四個位元組開始 的H.264格式問題
valid_len,
g_userts);
}
else if (valid_len > MAX_RTP_PKT_LENGTH)
{
//切分為很多個包發送,每個包前要對頭進行處理,如第一個包
valid_len -= 1;
int k=0,l=0;
k=valid_len/MAX_RTP_PKT_LENGTH;
l=valid_len%MAX_RTP_PKT_LENGTH;
int t=0;
int pos=5;
if(l!=0)
{
k=k+1;
}
while(t<k)//||(t==k&&l>0))
{
if(t<(k-1))//(t<k&&l!=0)||(t<(k-1))&&(l==0))//(0==t)||(t<k&&0!=l))
{
buffer[pos-2]=(NALU & 0x60)|28;//把包的幀類型設定為RTP類型
buffer[pos-1]=(NALU & 0x1f);
if(0==t)
{
buffer[pos-1]|=0x80;
}
sendBytes = rtp_session_send_with_ts(session,
&buffer[pos-2],
MAX_RTP_PKT_LENGTH+2,
g_userts);
t++;
pos+=MAX_RTP_PKT_LENGTH;
}
else //if((k==t&&l>0)||((t==k-1)&&l==0))
{
int iSendLen;
if(l>0)
{
iSendLen=valid_len-t*MAX_RTP_PKT_LENGTH;
}
else
iSendLen=MAX_RTP_PKT_LENGTH;
buffer[pos-2]=(NALU & 0x60)|28;
buffer[pos-1]=(NALU & 0x1f);
buffer[pos-1]|=0x40;//重要等級提1
sendBytes = rtp_session_send_with_ts(session,
&buffer[pos-2],
iSendLen+2,
g_userts);
t++;
}
}
}
g_userts += DefaultTimestampIncrement;//timestamp increase
return len;
}
#endif
4、VLC播放器的配置檔案sdp
配置檔案sdp;是一種格式,到時候VCL來以什麼格式來解析。
m=video 8080 RTP/AVP 96 m表示内容 8080端口 RTP傳輸協定 96傳輸内容的協定
a=rtpmap:96 H264
a=framerate:25 幀率
c=IN IP4 192.168.1.20 IPV4的格式化,和本地的IP位址