朱老师, 3518e系列,第三季
第一节: ORTP 引入。
1、传输的协议: http, ftp , rtp , rtsp .
2、 ORTP 是C实现的 RTP 库,实质是一个 服务器。
3、 实现局域网传输。
第二节: ORTP 库的移植。
1、 下载+解压。
下载网址。
GitHub - dmonakhov/ortp: mirror of linphone's git tree
上传加解压。
2、 修改源码
主要是增加 h264 的支持。
路径: src/avprofile.c
3、 编译。
注意: 我这里的编译 是在 hi3516cv610 的环境中编译的。
53 ./autogen.sh54 ./configure --prefix=./tmp/install --host=arm-linux-musleabi55 ./configure --prefix=/home/topeet/source_code/ortp-master/tmp/install --host=arm-linux-musleabi
有报错:
CC payloadtype.loCC rtpprofile.loCC rtcp.lo
In function 'rtcp_app_init',inlined from 'rtp_session_send_rtcp_APP' at rtcp.c:439:13:
rtcp.c:352:2: error: 'strncpy' specified bound 4 equals destination size [-Werror=stringop-truncation]352 | strncpy(app->name,name,4);| ^~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
make[3]: *** [Makefile:589: rtcp.lo] Error 1
make[3]: Leaving directory '/home/topeet/source_code/ortp-master/src'
make[2]: *** [Makefile:608: all-recursive] Error 1
make[2]: Leaving directory '/home/topeet/source_code/ortp-master/src'
make[1]: *** [Makefile:530: all-recursive] Error 1
make[1]: Leaving directory '/home/topeet/source_code/ortp-master'
make: *** [Makefile:414: all] Error 2
root@topeet:/home/topeet/source_code/ortp-master#
stun.c: In function 'stunCalculateIntegrity_longterm':
stun.c:1275:4: error: 'strncpy' output truncated before terminating nul copying 20 bytes from a string of the same length [-Werror=stringop-truncation]1275 | strncpy(hmac,"hmac-not-implemented",20);| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
stun.c: In function 'stunCalculateIntegrity_shortterm':
stun.c:1280:4: error: 'strncpy' output truncated before terminating nul copying 20 bytes from a string of the same length [-Werror=stringop-truncation]1280 | strncpy(hmac,"hmac-not-implemented",20);| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
make[3]: *** [Makefile:589: stun.lo] Error 1
make[3]: Leaving directory '/home/topeet/source_code/ortp-master/src'
make[2]: *** [Makefile:608: all-recursive] Error 1
make[2]: Leaving directory '/home/topeet/source_code/ortp-master/src'
make[1]: *** [Makefile:530: all-recursive] Error 1
make[1]: Leaving directory '/home/topeet/source_code/ortp-master'
make: *** [Makefile:414: all] Error 2
解决:
make clean
./configure --prefix=/home/topeet/source_code/ortp-master/tmp/install --host=arm-linux-musleabi CFLAGS="-Wno-error=array-bounds" CFLAGS="-Wno-stringop-truncation"
make
make install
编译成功。
第三节: RTP 传输视频实战。
1、 在 SDK sample 中 添加 rtp 传输的代码。
首先是 Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc/sample_venc.c 文件。
视频中 添加了 s32ChnNum 等于1 , 就是 压缩生成一路视频,原来是 生成了三路视频。
但是 这里我就不改了。
然后是,Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common/sample_comm_venc.c 文件,
这个文件主要设计到 对 ortp 服务器的 改动。
在 第一个 函数开始之前添加。
#define ORTP_ENABLE 1#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: */
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);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];//如果数据小于MAX_RTP_PKT_LENGTH字节,直接发送:单一NAL单元模式if(valid_len <= MAX_RTP_PKT_LENGTH){sendBytes = rtp_session_send_with_ts(session,&buffer[4],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;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;}elseiSendLen=MAX_RTP_PKT_LENGTH;buffer[pos-2]=(NALU & 0x60)|28;buffer[pos-1]=(NALU & 0x1f);buffer[pos-1]|=0x40;sendBytes = rtp_session_send_with_ts(session,&buffer[pos-2],iSendLen+2,g_userts);t++;}}}g_userts += DefaultTimestampIncrement;//timestamp increasereturn len;
}
#endif
这段添加 , 我跟 视频中的添加 是一样的。
然后还在 在这个文件中添加。
视频中添加的是 S32 SAMPLE_COMM_VENC_SaVeH264 这个函数。
但是我不应该添加这个函数。
我添加的地方是。 sample_comm_venc_save_stream 这个函数。
7 td_s32 sample_comm_venc_save_stream(FILE *fd, ot_venc_stream *stream)6 {5 td_u32 i;43 for (i = 0; i < stream->pack_cnt; i++) {2 #if ORTP_ENABLE1 rtpSend(pRtpSession,pstStream->pstPack[i].pu8Addr, pstStream->pstPack[i].u32Len);659 #else1 (td_void)fwrite(stream->pack[i].addr + stream->pack[i].offset,2 stream->pack[i].len - stream->pack[i].offset, 1, fd);3 (td_void)fflush(fd);4 #endif5 }67 return TD_SUCCESS;8 }9
然后还要再这个 文件中改一个地方,
视频中是这个文件, SAMPLE_COMM_VENC_GetVencStreamProc(HI VOID *p) 。
我自己的改的是这个文件,
7 static td_s32 sample_comm_get_stream_from_one_channl(sample_comm_venc_stream_proc_info *stream_proc_info, td_s32 index,6 ot_venc_stream_buf_info *stream_buf_info, ot_payload_type *payload_type)5 {4 td_s32 ret;3 ot_venc_stream stream;2 ot_venc_chn_status stat;127961 #if ORTP_ENABLE2 /***rtp init****/3 pRtpSession = rtpInit( LOCAL_HOST_IP ,8080);4 if (pRtpSession==NULL)5 {6 printf( "error rtpInit" );7 exit(-1);8 return 0;9 }10 #endif111213 /* step 2.1 : query how many packs in one-frame stream. */14 if (memset_s(&stream, sizeof(stream), 0, sizeof(stream)) != EOK) {15 printf("call memset_s error\n");16 }1718 ret = ss_mpi_venc_query_status(index, &stat);19 if (ret != TD_SUCCESS) {20 sample_print("ss_mpi_venc_query_status chn[%d] failed with %#x!\n", index, ret);21 return SAMPLE_RETURN_BREAK;22 }2324 if (stat.cur_packs == 0) {25 sample_print("NOTE: current frame is TD_NULL!\n");26 return SAMPLE_RETURN_CONTINUE;27 }
到这里 就改完了。
2、 从新编译sample
首先是, ortp 头文件的复制。
ortp 库的链接。
我自己是这个添加的,因为我没有 找到 头文件的设置,直接再 make 中添加的。
修改的文件是,Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/smp_linux.mak
1413 # target source12 OBJS := $(SMP_SRCS:%.c=%.o)1110 CFLAGS += $(COMM_INC)98 MPI_LIBS += $(LIBS_LD_CFLAGS)76 .PHONY : clean all54 all: $(TARGET)32 $(TARGET):$(COMM_OBJ) $(OBJS)1 @$(CC) $(CFLAGS) -o $(TARGET_PATH)/$@ $^ -Wl,--start-group $(MPI_LIBS) $(SENSOR_LIBS) $(AUDIO_LIBA) $(REL_LIB)/libsecurec.a -I/home/topeet/source_code/ortp-master/tmp/install/includ e/ -L/home/topeet/source_code/ortp-master/tmp/install/lib -lortp -lm -lc -Wl,--end-group151 clean:2 @rm -f $(TARGET_PATH)/$(TARGET)3 @rm -f $(OBJS)4 @rm -f $(COMM_OBJ)56 cleanstream:7 @rm -f *.h2648 @rm -f *.h2659 @rm -f *.jpg10 @rm -f *.mjp11 @rm -f *.mp4
~
编译测试一下看看。
有报错
_SDK_V1.0.1.0/smp/a7_linux/source/out/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include/exp_inc -DVER_X=1 -DVER_Y=0 -DVER_Z=0 -DVER_P=0 -DVER_B=10 -DUSER_BIT_32 -DKERNEL_BIT_32 -DOT_RELEASE -Wno-date-time -DSENSOR0_TYPE=SC4336P_MIPI_4M_30FPS_10BIT -DSENSOR1_TYPE=SC4336P_MIPI_4M_30FPS_10BIT -DBOARD_TYPE=DMEB_QFN -DOT_ACODEC_TYPE_INNER -DOT_VQE_USE_STATIC_MODULE_REGISTER -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc/../common -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc/../audio/adp -c -o /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc/../common/sample_comm_venc.o /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc/../common/sample_comm_venc.c
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc/../common/sample_comm_venc.c:45:10: fatal error: ortp/ortp.h: No such file or directory45 | #include <ortp/ortp.h>| ^~~~~~~~~~~~~
compilation terminated.
解决:
我一共做了 三次 makfile 的修改。
首先是 common/ 目录下, 因为源文件再这个目录。
目录下的makefile 成了 这样。
param_file=$(realpath $(dir $(firstword $(MAKEFILE_LIST))))/../Makefile.param
include $(param_file)
DEF_FLAGS := _GNU_SOURCE
#topeet wang added
WFLAGS += -I/home/topeet/source_code/ortp-master/tmp/install/include
WCOMM_INC += -L/home/topeet/source_code/ortp-master/tmp/install/lib
.PHONY : clean all
all:$(COMM_OBJ)clean:@rm $(COMM_OBJ) -f%.o:%.c@$(CC) $(COMM_INC) $(CFLAGS) $(WFLAGS) $(WCOMM_INC) -c $< -o $@ -lortp
然后是 sample 目录下的, makefile.param
这是我的添加。
9 INC_FLAGS := -I$(REL_INC)8 INC_FLAGS += -I$(REL_INC)7 INC_FLAGS += -I$(SDK_PATH)/$(EXTDRV)/es838865 ISP_VERSION := ISP_V243 CFLAGS += -Wall $(INC_FLAGS) -D$(OT_ARCH) -D$(OT_FPGA) -D$(ISP_VERSION)21 #topeet wang added94 CFLAGS += -I/home/topeet/source_code/ortp-master/tmp/install/include1 CFLAGS += -L/home/topeet/source_code/ortp-master/tmp/install/lib2345 CFLAGS += -lstdc++6 ifneq ($(CONFIG_LLVM), y)7 CFLAGS += -lpthread -lm -ldl8 endif9 CFLAGS += $(LIBS_CFLAGS)10 CFLAGS += $(LIBS_EXEC_CFLAGS)11 CFLAGS += $(MPP_CFLAGS)12 CFLAGS += -DSENSOR0_TYPE=$(SENSOR0_TYPE)13 CFLAGS += -DSENSOR1_TYPE=$(SENSOR1_TYPE)14 CFLAGS += -DBOARD_TYPE=$(BOARD_TYPE)15
然后是 sample 下的 smp_linux_mk
1312 # target source11 OBJS := $(SMP_SRCS:%.c=%.o)109 CFLAGS += $(COMM_INC)87 MPI_LIBS += $(LIBS_LD_CFLAGS)65 .PHONY : clean all43 all: $(TARGET)21 $(TARGET):$(COMM_OBJ) $(OBJS)14 @$(CC) $(CFLAGS) -o $(TARGET_PATH)/$@ $^ -Wl,--start-group $(MPI_LIBS) $(SENSOR_LIBS) $(AUDIO_LIBA) $(REL_LIB)/libsecurec.a -lortp -lm -lc -Wl,--end-group12 clean:3 @rm -f $(TARGET_PATH)/$(TARGET)4 @rm -f $(OBJS)5 @rm -f $(COMM_OBJ)67 cleanstream:8 @rm -f *.h2649 @rm -f *.h26510 @rm -f *.jpg11 @rm -f *.mjp12 @rm -f *.mp4
~
~
~
~
目前 我编译 整个sample 的话,会报错。
~~~~~~~~~~Start build bcd~~~~~~~~~~
make[1]: Entering directory '/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/bcd'
arm-v01c02-linux-musleabi-gcc -DSC4336P_MIPI_4M_30FPS_10BIT_SELECT=y -DSC4336P_MIPI_4M_30FPS_10BIT_SELECT=y -Wall -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/vendor/extdrv/es8388 -Dhi3516cv610 -DOT_XXXX -DISP_V2 -I/home/topeet/source_code/ortp-master/tmp/install/include -L/home/topeet/source_code/ortp-master/tmp/install/lib -lstdc++ -lpthread -lm -ldl -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fsigned-char -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/osal/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/platform/securec/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include/exp_inc -fstack-protector-strong -fPIC -ffunction-sections -fdata-sections -Os -mthumb -fno-aggressive-loop-optimizations -mcpu=cortex-a7 -mfloat-abi=softfp -mfpu=neon-vfpv4 -fPIE -pie -s -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fsigned-char -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/osal/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/platform/securec/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include/exp_inc -DVER_X=1 -DVER_Y=0 -DVER_Z=0 -DVER_P=0 -DVER_B=10 -DUSER_BIT_32 -DKERNEL_BIT_32 -DOT_RELEASE -Wno-date-time -DSENSOR0_TYPE=SC4336P_MIPI_4M_30FPS_10BIT -DSENSOR1_TYPE=SC4336P_MIPI_4M_30FPS_10BIT -DBOARD_TYPE=DMEB_QFN -DOT_ACODEC_TYPE_INNER -DOT_VQE_USE_STATIC_MODULE_REGISTER -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/bcd/../common -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/bcd/../audio/adp -c -o sample_bcd.o sample_bcd.c
make[1]: Leaving directory '/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/bcd'
~~~~~~~~~~Start build calcflicker~~~~~~~~~~
make[1]: Entering directory '/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/calcflicker'
arm-v01c02-linux-musleabi-gcc -DSC4336P_MIPI_4M_30FPS_10BIT_SELECT=y -DSC4336P_MIPI_4M_30FPS_10BIT_SELECT=y -Wall -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/vendor/extdrv/es8388 -Dhi3516cv610 -DOT_XXXX -DISP_V2 -I/home/topeet/source_code/ortp-master/tmp/install/include -L/home/topeet/source_code/ortp-master/tmp/install/lib -lstdc++ -lpthread -lm -ldl -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fsigned-char -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/osal/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/platform/securec/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include/exp_inc -fstack-protector-strong -fPIC -ffunction-sections -fdata-sections -Os -mthumb -fno-aggressive-loop-optimizations -mcpu=cortex-a7 -mfloat-abi=softfp -mfpu=neon-vfpv4 -fPIE -pie -s -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fsigned-char -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/osal/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/platform/securec/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include/exp_inc -DVER_X=1 -DVER_Y=0 -DVER_Z=0 -DVER_P=0 -DVER_B=10 -DUSER_BIT_32 -DKERNEL_BIT_32 -DOT_RELEASE -Wno-date-time -DSENSOR0_TYPE=SC4336P_MIPI_4M_30FPS_10BIT -DSENSOR1_TYPE=SC4336P_MIPI_4M_30FPS_10BIT -DBOARD_TYPE=DMEB_QFN -DOT_ACODEC_TYPE_INNER -DOT_VQE_USE_STATIC_MODULE_REGISTER -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/calcflicker/../common -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/calcflicker/../audio/adp -c -o /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/calcflicker/sample_calcflicker.o /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/calcflicker/sample_calcflicker.c
make[1]: Leaving directory '/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/calcflicker'
~~~~~~~~~~Start build fast_ae~~~~~~~~~~
make[1]: Entering directory '/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/fast_ae'
arm-v01c02-linux-musleabi-gcc -DSC4336P_MIPI_4M_30FPS_10BIT_SELECT=y -DSC4336P_MIPI_4M_30FPS_10BIT_SELECT=y -Wall -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/vendor/extdrv/es8388 -Dhi3516cv610 -DOT_XXXX -DISP_V2 -I/home/topeet/source_code/ortp-master/tmp/install/include -L/home/topeet/source_code/ortp-master/tmp/install/lib -lstdc++ -lpthread -lm -ldl -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fsigned-char -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/osal/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/platform/securec/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include/exp_inc -fstack-protector-strong -fPIC -ffunction-sections -fdata-sections -Os -mthumb -fno-aggressive-loop-optimizations -mcpu=cortex-a7 -mfloat-abi=softfp -mfpu=neon-vfpv4 -fPIE -pie -s -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fsigned-char -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/osal/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/platform/securec/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include/exp_inc -DVER_X=1 -DVER_Y=0 -DVER_Z=0 -DVER_P=0 -DVER_B=10 -DUSER_BIT_32 -DKERNEL_BIT_32 -DOT_RELEASE -Wno-date-time -DSENSOR0_TYPE=SC4336P_MIPI_4M_30FPS_10BIT -DSENSOR1_TYPE=SC4336P_MIPI_4M_30FPS_10BIT -DBOARD_TYPE=DMEB_QFN -DOT_ACODEC_TYPE_INNER -DOT_VQE_USE_STATIC_MODULE_REGISTER -static -ffunction-sections -fdata-sections -Wl,--gc-sections -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/fast_ae/../common -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/fast_ae/../audio/adp -c -o /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/fast_ae/sample_fast_ae.o /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/fast_ae/sample_fast_ae.c
arm-v01c02-linux-musleabi-gcc -DSC4336P_MIPI_4M_30FPS_10BIT_SELECT=y -DSC4336P_MIPI_4M_30FPS_10BIT_SELECT=y -Wall -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/vendor/extdrv/es8388 -Dhi3516cv610 -DOT_XXXX -DISP_V2 -I/home/topeet/source_code/ortp-master/tmp/install/include -L/home/topeet/source_code/ortp-master/tmp/install/lib -lstdc++ -lpthread -lm -ldl -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fsigned-char -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/osal/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/platform/securec/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include/exp_inc -fstack-protector-strong -fPIC -ffunction-sections -fdata-sections -Os -mthumb -fno-aggressive-loop-optimizations -mcpu=cortex-a7 -mfloat-abi=softfp -mfpu=neon-vfpv4 -fPIE -pie -s -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fsigned-char -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/osal/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/platform/securec/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include/exp_inc -DVER_X=1 -DVER_Y=0 -DVER_Z=0 -DVER_P=0 -DVER_B=10 -DUSER_BIT_32 -DKERNEL_BIT_32 -DOT_RELEASE -Wno-date-time -DSENSOR0_TYPE=SC4336P_MIPI_4M_30FPS_10BIT -DSENSOR1_TYPE=SC4336P_MIPI_4M_30FPS_10BIT -DBOARD_TYPE=DMEB_QFN -DOT_ACODEC_TYPE_INNER -DOT_VQE_USE_STATIC_MODULE_REGISTER -static -ffunction-sections -fdata-sections -Wl,--gc-sections -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/fast_ae/../common -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/fast_ae/../audio/adp -c -o /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/fast_ae/sc4336p_sensor_init.o /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/fast_ae/sc4336p_sensor_init.c
/opt/linux/x86-arm/arm-v01c02-linux-musleabi-gcc/bin/../lib/gcc/arm-linux-musleabi/10.3.0/../../../../arm-linux-musleabi/bin/ld: cannot find -lortp: No such file or directory
collect2: error: ld returned 1 exit status
make[1]: *** [/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/fast_ae/../smp_linux.mak:14: sample_fast_ae] Error 1
make[1]: Leaving directory '/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/fast_ae'
make: *** [Makefile:31: fast_ae] Error 2
这意思是 我编译 某个 目录的话,编译不成功。
但是 我测试 , common 目录 + venc 目录可以编译成功,
具体原因不清楚,可能与 因为是动态链接有关系, 因为有的 文件,依赖 common 文件夹。
报错也是 ld 的错误,而不是 gcc 的错误。
先不管了,先测试。
3、将编译出来的 ortp 的源码 拷贝到 开发板。
将Lib 库中的 so 文件 全部拷贝到 开发板的 usr/lib 目录下。
运行程序后有报错。
如果是 不运行 uvc 摄像头的程序的话,是这个报错。
~ # ./sample_venc 0
open sys: No such file or directory
sample_comm_vpss_get_wrap_cfg: get buf line failed
open sys: No such file or directory
open err
: No such file or directory
open err
: No such file or directory
[sample_comm_sys_init_with_vb_supplement]-289: ss_mpi_vb_set_conf failed!
[sample_venc_online_wrap_sys_init]-999: sample_venc_sys_init failed!
open sys: No such file or directory
[sample_comm_vi_set_vi_vpss_mode]-871: set vi vpss mode failed!
open sys: No such file or directory
open err
: No such file or directory
[sample_venc_online_wrap_start_sys_vi_vpss]-1093: Init SYS err for 0xffffffff!
program exit abnormally!
~ #
运行 uvc 程序之后 是这个报错。
~ # ./sample_venc 0
wrap online is 1, buf line is 128, buf size is 458544[MPP] Version: [HI3516CV610_MPP_V1.0.1.0 B040 Release], Build Time[Sep 7 2024, 17:51:12]linear mode
===================================================================================
vi_pipe:0,== SC4336P_MIPI_27Minput_2lane_10bit_630Mbps_2560x1440_30fps Init OK! ==
===================================================================================
ISP Dev 0 running !
please input choose gop mode!0) normal p.1) dual p.2) smart p.
random: crng init done
0
please input choose rc mode!c) cbr.v) vbr.b) abr.a) avbr.x) cvbr.q) qvbr.f) fix_qp
c
********oRTP for H.264 Init********
please press twice ENTER to exit this sample
ortp-message-Setting random local addresses.
ortp-message-Using permissive algorithm
ortp-warning-Error sending rtp packet: Network unreachable ; socket=23
ortp-warning-Error sending rtp packet: Network unreachable ; socket=23
ortp-warning-Error sending rtp packet: Network unreachable ; socket=23
ortp-warning-Error sending rtp packet: Network unreachable ; socket=23
ortp-warning-Error sending rtp packet: Network unreachable ; socket=23
ortp-warning-Error sending rtp packet: Network unreachable ; socket=23
ortp-warning-Error sending rtp packet: Network unreachable ; socket=23
ortp-warning-Error sending rtp packet: Network unreachable ; socket=23
ortp-warning-Error sending rtp packet: Network unreachable ; socket=23
ortp-warning-Error sending rtp packet: Network unreachable ; socket=23
ortp-warning-Error sending rtp packet: Network unreachable ; socket=23
但是 感觉这个报错 应该好改。
目前 更改了应用程序的ip , VLC的ip
可以出图了,但是 画面看不清。
结果是这样的。
第四节 , ortp 的源码的分析一:
ORTP 是一个 开源库,
里面有一个test 目录。
就从 测试 案例入手。
ortp 实现了 rtp , rtcp 协议。
rtp 负责传输。
rtcp 负责 控制。
首先找到 main 函数。
然后看一下 ortp_init()函数
这个函数 最重要的是 av_profile_init, 这里面 有各种压缩协议。
ortp_global_stats_reset , 初始化了全局变量,就是清零。
init_random_number_generator, 这是一个 随机数发生器。
然后是 ortp_scheduler_init 函数。
这个函数是一个定时器,时间到了 ,这里就是对定时器的初始化。
就会轮流执行 session.
一个session 就是一个 网络链接。
这里就开始 创建会话了。
rtp_session_new , 创建了一个session, 并且 初始化了 这个结构体。
下面的这几句,依然是在对 结构体的设置。
这里, SSRC 的目的是为了是 接收端,区分出不同的session。
这个变量可有可无,就看你 是不是需要 拿出一包数据,并且想知道 这包数据是哪个session 的。
这里 fopen 打开的是一个文件。
signal ,这里再定义一个 信号的 回调函数。
fread 这里 读一次 发一次。
rtp_session_send_with_ts 是发送函数。
这里 rtp_session_create_packet, 会创建好, packet, 就是再信息上加上头。
rtp_session_sendm_with_ts , 最终会 调用 sendto 函数 使用 socket 发送出去。
utils.c 实现了双向链表。
str_util.c 实现了队列的管理。
rtpparse.c rtcpparse.c 实现了 ortp 的 解包。
jitterctrl.c 实现了 jitter buffer 的防抖,因为再 3G , wifi 环境下容易断链 , 通过 防抖实现 音视频的传输的平滑。
默认的延时是比较大的, 如果要想修改成延时小的,就要 修改这些 数据结构。
但是我暂时不去看这些。
第六节, ORTP的发送实验的源码的 解析一 + 解析二。
sample_venc.c 他改的 是编码的通道, 改的是 s32ChnNum 的值。
改动的主要地方 在文件 sample_comm_venc.c 中
#define ORTP_ENABLE 1#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: */
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);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];//如果数据小于MAX_RTP_PKT_LENGTH字节,直接发送:单一NAL单元模式if(valid_len <= MAX_RTP_PKT_LENGTH){sendBytes = rtp_session_send_with_ts(session,&buffer[4],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;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;}elseiSendLen=MAX_RTP_PKT_LENGTH;buffer[pos-2]=(NALU & 0x60)|28;buffer[pos-1]=(NALU & 0x1f);buffer[pos-1]|=0x40;sendBytes = rtp_session_send_with_ts(session,&buffer[pos-2],iSendLen+2,g_userts);t++;}}}g_userts += DefaultTimestampIncrement;//timestamp increasereturn len;
}
#endif
这里 添加了一个 宏定义, ORTP_ENABLE , 只要设置为0 , 所有的代码就不执行了。可以学习一下这个。
主要的函数有 rtpinit() , rtpexit() , rtpsend()
然后 在 getvencstream 中 添加了 rtpinit .
看看 rtpinit() .
ortP_init() , 分配 结构体,并对结构体 赋初值。
ortp_scheduler_init(), 初始化了一个定时器。用于不同的session 的调度。
rtp_session_new, 创建了一个session, 只是 用于发送。
rtp_session_set_scheduling_mode , 就是 决定 是否 使用这种调度。
这里 注释掉了 rtp_session_set_connected_mode , 它的作用是, 使用 udp 还是 tcp, 默认应该是 udp.
rtp_session_set_remote-addr , 这是在设置 发送目的地的 ip+端口。
rtp_session_set_payloard_type ,这是在配置 264 的格式。
rtp_sessoin_set_ssrc , 在对 SSRC进行配置。
然后还在 函数 sample_comm_venc_saveh264 函数中 做了修改。
/******************************************************************************
* funciton : save H264 stream
******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_SaveH264(FILE* fpH264File, VENC_STREAM_S *pstStream)
{HI_S32 i;for (i = 0; i < pstStream->u32PackCount; i++){#if ORTP_ENABLErtpSend(pRtpSession,pstStream->pstPack[i].pu8Addr, pstStream->pstPack[i].u32Len);#elsefwrite(pstStream->pstPack[i].pu8Addr+pstStream->pstPack[i].u32Offset,pstStream->pstPack[i].u32Len-pstStream->pstPack[i].u32Offset, 1, fpH264File);fflush(fpH264File);#endif}return HI_SUCCESS;
}
这里 主要就是 把 本来应该 写到 文件里的内容 , 通过socket 发送出去了。
之所以 在 fwrite 的时候 多了个 pstStream->pstPack[i].u32Offset 这个 offset 是因为, 对于文件,每次写, 都要移动 指针,否则会覆盖, 但是 socket 发送就不用了。
关键的函数是 rtpsend 函数。
/** 发送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];//如果数据小于MAX_RTP_PKT_LENGTH字节,直接发送:单一NAL单元模式if(valid_len <= MAX_RTP_PKT_LENGTH){sendBytes = rtp_session_send_with_ts(session,&buffer[4],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;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;}elseiSendLen=MAX_RTP_PKT_LENGTH;buffer[pos-2]=(NALU & 0x60)|28;buffer[pos-1]=(NALU & 0x1f);buffer[pos-1]|=0x40;sendBytes = rtp_session_send_with_ts(session,&buffer[pos-2],iSendLen+2,g_userts);t++;}}}g_userts += DefaultTimestampIncrement;//timestamp increasereturn len;
}
这个函数 主要考虑了 包的拆开发送。
这里发送的长度最大是 MAX_RTP_PKT_LENGTH
这里的 1400 是经验值, 如果网络好,就可以大一点,如果网络不好就要小一点,如果丢包了,还可以重传。
这里 为什么是 buffer[4] 呢, 因为,如果是 一包不到最大值的话,那么就不需要 NAL了, NAL 正好是 4个字节。
对于需要拆包的包,就到了这个循环。 这里主要在计算 有几个完整的包, 最后剩下了几个字节。
这里 如果是 分包了, 那么就要加上 NAL了, NAL是一个字节的长度。加上 两个NAL。
NAL 具体的 位定义 先不去管。
NAL & 60 | 28 , 这里就是 设置了优先级, 并且 设置了 h264
NAL & 0x1f , 这里 是保存了 最原始的 NAL。
一共添加了 两个NAL。
总结:
在buffer 中,
buffer[0], buffer[1],buffer[2],buffer[3] 。
buffer[4] 。
他发送 是 从 buffer[3] 开始发送的。
这里理解的有些乱, 先过。
最终使用 rtp_session_send_with_ts 发送出去。
这里是在操作 最后 剩下的 一个包。
这里对 buffer[pos-1 ] 操作了两次,
看来只要 对 后5位 保持原装就可以了。
第八节, vlc 的使用。
主要是 sdp 文件的配置。
这里需要注意, 114 ,是 ortp 的 发送目的的ip , 这里的 vlc 有点 截流的意思。
第九节, 这里就是 我自己在 3516 的SDK 中的改动了。
依然是使用的是 ortp .
改动如下。
sample_venc.c 中 并没有做改动。
所有的改动 都在 sample_comm_venc.c 中了。
首先在第一个函数之前添加这些。
#define ORTP_ENABLE 1#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: */
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);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];//如果数据小于MAX_RTP_PKT_LENGTH字节,直接发送:单一NAL单元模式if(valid_len <= MAX_RTP_PKT_LENGTH){sendBytes = rtp_session_send_with_ts(session,&buffer[4],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;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;}elseiSendLen=MAX_RTP_PKT_LENGTH;buffer[pos-2]=(NALU & 0x60)|28;buffer[pos-1]=(NALU & 0x1f);buffer[pos-1]|=0x40;sendBytes = rtp_session_send_with_ts(session,&buffer[pos-2],iSendLen+2,g_userts);t++;}}}g_userts += DefaultTimestampIncrement;//timestamp increasereturn len;
}
#endif
然后再 save_stream 中添加这些。
23 td_s32 sample_comm_venc_save_stream(FILE *fd, ot_venc_stream *stream)22 {21 td_u32 i;2019 for (i = 0; i < stream->pack_cnt; i++) {18 #if ORTP_ENABLE17 rtpSend(pRtpSession,stream->pack[i].addr, stream->pack[i].len);16 #else15 (td_void)fwrite(stream->pack[i].addr + stream->pack[i].offset,14 stream->pack[i].len - stream->pack[i].offset, 1, fd);13 (td_void)fflush(fd);12 #endif11 }109 return TD_SUCCESS;8 }7
然后再 save_stream 中 添加 rtpsend, 取代写文件。
1 td_s32 sample_comm_venc_save_stream(FILE *fd, ot_venc_stream *stream)2 {3 td_u32 i;45 for (i = 0; i < stream->pack_cnt; i++) {6 #if ORTP_ENABLE7 rtpSend(pRtpSession,stream->pack[i].addr, stream->pack[i].len);8 #else9 (td_void)fwrite(stream->pack[i].addr + stream->pack[i].offset,10 stream->pack[i].len - stream->pack[i].offset, 1, fd);11 (td_void)fflush(fd);12 #endif13 }1415 return TD_SUCCESS;16 }17
比较关键的还有这一条。 如果 既有 h264, 又有 h265的话, 会将两种压缩的pack 都发出去,这跟我的 rtpsend 的添加的位置有关.
这里如果 我 不去掉 h265 的话,就会出现前面的 虽然传输成功,但是 花屏的 效果,会有前面的传输的报错。
所以 这里 就使能了一路 venc
22 static td_void sample_comm_fd_isset(sample_comm_venc_stream_proc_info *stream_proc_info, fd_set *read_fds,21 ot_venc_stream_buf_info *stream_buf_info, ot_payload_type *payload_type, sample_venc_getstream_para *para)20 {19 td_s32 i, ret;1817 // for (i = 0; (i < stream_proc_info->chn_total) && (i < OT_VENC_MAX_CHN_NUM); i++) {16 //15 //topeet wang added14 for (i = 1; (i < stream_proc_info->chn_total) && (i < OT_VENC_MAX_CHN_NUM); i++) {13 if (FD_ISSET(stream_proc_info->venc_fd[i], read_fds)) {12 stream_proc_info->venc_chn = para->venc_chn[i];11 ret = sample_comm_get_stream_from_one_channl(stream_proc_info, i, stream_buf_info, payload_type);10 if (ret == SAMPLE_RETURN_CONTINUE) {9 continue;8 } else if (ret == SAMPLE_RETURN_BREAK) {7 break;6 }5 }4 }3 }2
编译+烧写,
再编译的时候, 会有报错,参考前面的 记录。
然后再次执行
~ # ./sample_venc 0
wrap online is 1, buf line is 128, buf size is 458544[MPP] Version: [HI3516CV610_MPP_V1.0.1.0 B040 Release], Build Time[Sep 7 2024, 17:51:12]linear mode
===================================================================================
vi_pipe:0,== SC4336P_MIPI_27Minput_2lane_10bit_630Mbps_2560x1440_30fps Init OK! ==
===================================================================================
ISP Dev 0 running !
please input choose gop mode!0) normal p.1) dual p.2) smart p.
0
please input choose rc mode!c) cbr.v) vbr.b) abr.a) avbr.x) cvbr.q) qvbr.f) fix_qp
c
********oRTP for H.264 Init********
ortp-message-Setting random local addresses.
ortp-message-Using permissive algorithm
please press twice ENTER to exit this sample
^C^Cprogram exit normally!
~ #
vlc 的配置。
m=video 8080 RTP/AVP 96
a=rtpmap:96 H264
a=framerate:30
c=IN IP4 192.168.1.114
便可以 出图。
问题依然是延迟比较严重。
但是 不管它,反正 通了。