最近在串一个基于live555的rtsp client,因为要连接camera sdk - rtsp client - live555,所以要写一个基于camerasdk的执行程序来call rtsp client的lib,rtsp client又要call live555的lib。顺便整理一下可执行程序链接动态库/静态库,以及如何生成动态库/静态库的过程;
live555源码如何编译:
1. 解压live555后,将config.armlinux中toolchain改成自己的,并添加-DLOCALE_NOT_USED -fPIC:
CROSS_COMPILE?= arm-linux-gnueabihf-
COMPILE_OPTS = $(INCLUDES) -I. -O2 -DSOCKLEN_T=socklen_t -DNO_SSTREAM=1 -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -DLOCALE_NOT_USED -fPIC
2.生成MakeFile并编译:
./genMakefiles armlinux
make
3.有一个release live555的脚本可以借鉴使用一下:
#!/bin/bash
mkdir Live555-LIB
export INSTALL_DIR=`pwd`/Live555-LIB
#create file
cd Live555-LIB
mkdir lib
mkdir bin
mkdir include
cd -
cd Live555-LIB/include
mkdir liveMedia
mkdir BasicUsageEnvironment
mkdir UsageEnvironment
mkdir groupsock
cd -
cd Live555-LIB/bin
mkdir testProgs
mkdir mediaServer
mkdir proxyServer
cd -
#copy include
cp liveMedia/include/*.hh Live555-LIB/include/liveMedia
cp BasicUsageEnvironment/include/*.hh Live555-LIB/include/BasicUsageEnvironment
cp UsageEnvironment/include/*.hh Live555-LIB/include/UsageEnvironment
cp groupsock/include/*.hh Live555-LIB/include/groupsock
#copy lib
cp liveMedia/libliveMedia.a Live555-LIB/lib
cp BasicUsageEnvironment/libBasicUsageEnvironment.a Live555-LIB/lib
cp UsageEnvironment/libUsageEnvironment.a Live555-LIB/lib
cp groupsock/libgroupsock.a Live555-LIB/lib
cd testProgs
cp MPEG2TransportStreamIndexer openRTSP playSIP registerRTSPStream sapWatch testAMRAudioStreamer testDVVideoStreamer testH264VideoStreamer testH264VideoToTransportStream testH265VideoStreamer testH265VideoToTransportStream testMKVStreamer testMP3Receiver testMP3Streamer testMPEG1or2AudioVideoStreamer testMPEG1or2ProgramToTransportStream testMPEG1or2Splitter testMPEG1or2VideoReceiver testMPEG1or2VideoStreamer testMPEG2TransportReceiver testMPEG2TransportStreamer testMPEG2TransportStreamTrickPlay testMPEG4VideoStreamer testOggStreamer testOnDemandRTSPServer testRelay testReplicator testRTSPClient testWAVAudioStreamer vobStreamer ../Live555-LIB/bin/testProgs/
cd -
cd mediaServer
cp live555MediaServer ../Live555-LIB/bin/mediaServer/
cd -
cd proxyServer
cp live555ProxyServer ../Live555-LIB/bin/proxyServer/
cd -
live555编译完成后,默认生成的是静态库。将生成的lib和include拷贝出来供rtsp client使用
rtsp client架构:
rtsp主要包含两个class:
RTSP_Stream_API:向上提供rtsp client api供camera可执行程序调用;
RtspClientStream:向下call live555 api实现rtsp;
makefile如下(默认是编译成静态库):
Makefile.inc:
SHELL = /bin/bash
CC := arm-linux-gnueabihf-gcc #gcc
CPP := arm-linux-gnueabihf-g++ #g++
LD := ld
AR := ar
STRIP := strip
CFLAGS += -c -g -Wall -fPIC -DWITH_DOM -DWITH_OPENSSL -DWITH_NO_C_LOCALE -D__STDC_CONSTANT_MACROS
CFLAGS += $(INCLUDE)
# 目标文件
OBJECTS_PATH := $(patsubst %.c,$(TEMPDIR)%.o,$(filter %.c, $(SOURCES_PATH)))
# 头文件路径
INCLUDE += -I../include
INCLUDE += -I../include/groupsock
INCLUDE += -I../include/liveMedia
INCLUDE += -I../include/UsageEnvironment
INCLUDE += -I../include/BasicUsageEnvironment
LBPATHQ = ../lib
# 链接动态库
#LDLIBS += -Wl,--whole-archive $(LBPATHQ)/libgroupsock.a \
# $(LBPATHQ)/libliveMedia.a \
# $(LBPATHQ)/libBasicUsageEnvironment.a \
# $(LBPATHQ)/libUsageEnvironment.a \
# -Wl,--no-whole-archive
LDLIBS += $(LBPATHQ)/libgroupsock.a \
$(LBPATHQ)/libliveMedia.a \
$(LBPATHQ)/libBasicUsageEnvironment.a \
$(LBPATHQ)/libUsageEnvironment.a
%.o: %.cpp
@echo " CPP " $@;
@$(CPP) $(CFLAGS) -c -o $@ $<
%.o: %.c
@echo " CC " $@;
@$(CC) $(CFLAGS) -c -o $@ $<
.PHONY: all clean
Makefile:
include ../Makefile.inc
PROGRAM = libRtspStream.a
SOURCES += RTSP_Stream_API.cpp
SOURCES += RtspClientMan.cpp
SOURCES += RtspClientStream.cpp
OBJECTS := $(patsubst %.cpp,$(TEMPDIR)%.o,$(filter %.cpp, $(SOURCES)))
all: $(OBJECTS_PATH) $(OBJECTS)
#link dynamic lib
#$(CPP) -shared-o $(PROGRAM) $(OBJECTS) $(LDLIBS)
#link static lib
@for var in $(LDLIBS); do ar x $$var; done
ar rcs $(PROGRAM) $(OBJECTS) *.o
rm -f *.o
clean:
rm -f $(OBJECTS)
rm -f $(PROGRAM)
改成动态库只需要将Makefile link static部分改成link dynamic即可。需要注意的是libRtspStream如果是动态库链接live555的静态库时只需要在编译的时候链接即可;如果libRtspStream是静态库链接live555的静态库时,不能直接链接,需要先用ar x将live555的静态库解压成.o文件,然后再跟libRtspStream生成的.o一起用ar rcs打包成libRtspStream.a才可以。
编译成动态库时,需要使用export LD_LIBRARY_PATH=$PWD:$LD_LIBRARY_PATH将动态库的路径导入到LIBPATH才能找到。
Camera SDK的可执行程序:
可执行程序在链接静态库和动态库时没有区别,具体Makefile如下:
CROSS_COMPILE ?=arm-linux-gnueabihf-
CC = $(CROSS_COMPILE)gcc
CPP = $(CROSS_COMPILE)g++
AR = $(CROSS_COMPILE)ar
COM_FLAGS = -Wall -O2 -fPIC -mcpu=cortex-a9 -mfpu=neon-fp16 -mfloat-abi=hard -mthumb-interwork -marm -O0 -w
C_FLAGS = $(COM_FLAGS)
CPP_FLAGS = $(COM_FLAGS)
#include ../Makefile.inc
INCLUDES += -I. -I../project/release/smartcar/include/
TARGET_NAME = rtspclient
#CPP_SRCS = testRTSPClient.cpp
C_SRCS = st_main.c st_common.c tem.c
CPP_OBJS = $(patsubst %.cpp, %.cpp.o, $(CPP_SRCS))
C_OBJS = $(patsubst %.c, %.c.o, $(C_SRCS))
LIB_PATH = -L./ -L../project/release/smartcar/i2/006A/glibc/4.8.3/lib/dynamic/
LIB_NAME += -lmi_venc -lmi_sys -lmi_vdec -lmi_divp -lRtspStream -lstdc++
.PHONY: all prepare clean
all: prepare $(TARGET_NAME) finish
prepare:
@echo
@echo ">>>>========================================================"
@echo "TARGET_NAME = $(TARGET_NAME)"
@echo
clean:
@rm -Rf $(CPP_OBJS)
@rm -f $(C_OBJS)
@rm -Rf $(TARGET_NAME)
finish:
@echo "make done"
@echo "<<<<========================================================"
@echo
$(TARGET_NAME): $(CPP_OBJS) $(CPP_SRCS) $(C_OBJS) $(C_SRCS)
@echo "generate $@"
@$(CC) -o $@ $(C_OBJS) $(CPP_OBJS) $(LIB_PATH) $(LIB_NAME) -lm -lpthread
%.c.o : %.c
@echo "compile $@"
@$(CC) $(C_FLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@
%.cpp.o : %.cpp
@echo "compile $@"
@$(CPP) $(CPP_FLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@
附赠一个usb升级包的脚本:
#!/bin/bash
#----------------------------------------
# PATH Define
#----------------------------------------
TARGET_DIR=./image/output/images
AUTO_UPDATE_SCRIPT=$TARGET_DIR/auto_update.txt
TMP_UPGRADE_FILE=TMP_MyUsbUpgrade.bin
PADDED_BIN=$TARGET_DIR/padded.bin
PAD_DUMMY_BIN=$TARGET_DIR/dummy_pad
UPGRADE_FILE=$TARGET_DIR/MyUsbUpgrade.bin
SCRIPT_FILE=$TARGET_DIR/upgrade_script.txt
#lunch `print_lunch_menu | grep aosp_$TARGET_DEVICE-userdebug | cut -d. -f1`
#----------------------------------------
# Globe Value Define
#----------------------------------------
SECURE_UPGRADE=0
USB_CRC_CHECK=0
SPILT_SIZE=16384
SCRIPT_SIZE=0x4000 #16KB
PAD_DUMMY_SIZE=10240 #10KB
currentImageOffset=$SCRIPT_SIZE
MAGIC_STRING=12345678
FullUpgrade="n"
#CRC_SEGMENT_SIZE should align to 0x1000
CRC_SEGMENT_SIZE=0x200000 #2MB
function func_process_main_script()
{
BUILD_TIME=`date '+%Y-%m-%d %T'`
BUILD_PATH=`pwd`
setpartition=0
#confirm each image is upgrade or not.
mainScript=""
tmp2="
"
tmpScript=$(grep "estar" $AUTO_UPDATE_SCRIPT | grep "\[\[")
for mainContent in $tmpScript
do
imageName=$(echo $mainContent | awk '{print $2}' | cut -d '/' -f 2)
read -p "Upgrade $imageName? (y/N)" temp
if [ "$temp" == "Y" ] || [ "$temp" == "y" ]; then
mainScript=$mainScript$mainContent$tmp2
fi
if [ "$imageName" == "[[set_partition.es" ]; then
setpartition=1
fi
done
#pad set_config to usb script
tmpScript=$(grep "set_config" $AUTO_UPDATE_SCRIPT)
mainScript=$mainScript$tmpScript
#pad set_partition to usb script
if [ "$setpartition" == "0" ]; then
tmpScript=$(grep "set_partition" $AUTO_UPDATE_SCRIPT)
mainScript=$tmpScript$tmp2$mainScript
fi
echo "UpgradeImage Generating....."
for mainContent in $mainScript
do
if [ "$(echo $mainContent | awk '{print $1}')" == "estar" ];then
func_process_sub_script $(echo $mainContent|awk '{print $2}')
else
if [ "$mainContent" != "reset" ] && [ "$mainContent" != "printenv" ] && [ "$mainContent" != "% <- this is end of file symbol" ];then
echo $mainContent >> $SCRIPT_FILE
fi
fi
done
}
function func_process_sub_script()
{
filePath=$1
fileName=$(echo $1 | cut -d '/' -f 2 | cut -d '[' -f 3)
echo "" >> $SCRIPT_FILE
echo "# File Partition: "$fileName >> $SCRIPT_FILE
filecontent=$(grep -Ev "^\s*$|#" $TARGET_DIR/$filePath)
for subContent in $filecontent
do
if [ "$subContent" != "% <- this is end of file symbol" ] && [ "$subContent" != "sync_mmap" ]; then
subContent_prefix=$(echo $subContent | awk '{print $1}')
if [ "$subContent_prefix" == "tftp" ]; then
DRAM_BUF_ADDR=$(echo $subContent | awk '{print $2}')
imagePath=$(echo $subContent | awk '{print $3}')
imageSize=$(stat -c%s $TARGET_DIR/$imagePath)
printf "fatload usb 0 %s \$(UpgradeImage) 0x%x 0x%x\n" $DRAM_BUF_ADDR $imageSize $currentImageOffset >> $SCRIPT_FILE
cat $TARGET_DIR/$imagePath >> $TMP_UPGRADE_FILE
# align image to 0x1000(4K)
ImageAlignSize=0
NOT_ALAIN_IMAGE_SIZE=$(($imageSize & 0xfff))
if [ $NOT_ALAIN_IMAGE_SIZE != 0 ]; then
ImageAlignSize=$((0x1000-$NOT_ALAIN_IMAGE_SIZE))
for ((i=0; i<$ImageAlignSize; i++))
do
printf "\xff" >>$PADDED_BIN
done
cat $PADDED_BIN >>$TMP_UPGRADE_FILE
rm $PADDED_BIN
fi
currentImageOffset=$(($currentImageOffset+$imageSize+$ImageAlignSize))
else
#fix ubi write 0x20400000 tvcustomer ${filesize} to ubi write 0x20400000 tvcustomer 0xfffff
#Begin
CMD=$(echo $subContent | awk '{print $2}')
if [ "$CMD" == "write.p" ] || [ "$CMD" == "write.boot" ] || [ "$CMD" == "unlzo" ] || [ "$CMD" == "unlzo.cont" ] || [ "$CMD" == "write.e" ] || [ "$CMD" == "write" ]; then
#change 10 mechanism to 16 mechanism
imageSize_16=0x$(echo "obase=16; $imageSize" | bc)
imageAddr=$(echo "$DRAM_BUF_ADDR")
subContent=${subContent/'$(filesize)'/$imageSize_16}
subContent=${subContent/'${filesize}'/$imageSize_16}
subContent=${subContent/'${fileaddr}'/$imageAddr}
fi
#fix nand write.e ${fileaddr} recovery $(filesize) to nand write.e xxx recovery xxx
#fix setenv recoverycmd nand read.e 0x25000000 recovery $(filesize) to setenv recoverycmd nand read.e 0x25000000 recovery xxx
CMD_NAND=$(echo $subContent | awk '{print $1}')
if [ "$CMD_NAND" == "ncishash" ] || [ "$CMD_NAND" == "setenv" ]; then
imageSize_16=0x$(echo "obase=16; $imageSize" | bc)
subContent=${subContent/'$(filesize)'/$imageSize_16}
fi
#End
subContent=$(echo $subContent | tr -d '\r\n')
echo $subContent >> $SCRIPT_FILE
fi
fi
done
}
function func_init()
{
# delete related file
rm -f $SCRIPT_FILE
rm -f $UPGRADE_FILE
rm -f $TMP_UPGRADE_FILE
#ANDROID_BUILD_TOP=`pwd`
#export PATH=$PATH:$ANDROID_BUILD_TOP/prebuilts/tools/linux-x86/crc
dos2unix $AUTO_UPDATE_SCRIPT $TARGET_DIR/scripts/* 1>/dev/null 2>&1
}
function func_generate_script_file()
{
echo "% <- this is end of script symbol" >>$SCRIPT_FILE
# pad script to script_file size
SCRIPT_FILE_SIZE=$(stat -c%s $SCRIPT_FILE)
PADDED_SIZE=$(($SCRIPT_SIZE-$SCRIPT_FILE_SIZE))
printf "\xff" >$PAD_DUMMY_BIN
for ((i=1; i<$PAD_DUMMY_SIZE; i++))
do
printf "\xff" >>$PAD_DUMMY_BIN
done
while [ $PADDED_SIZE -gt $PAD_DUMMY_SIZE ]
do
cat $PAD_DUMMY_BIN >> $SCRIPT_FILE
PADDED_SIZE=$(($PADDED_SIZE-$PAD_DUMMY_SIZE))
done
if [ $PADDED_SIZE != 0 ]; then
printf "\xff" >$PADDED_BIN
for ((i=1; i<$PADDED_SIZE; i++))
do
printf "\xff" >>$PADDED_BIN
done
cat $PADDED_BIN >> $SCRIPT_FILE
rm $PADDED_BIN
fi
}
function func_generate_upgrade_file()
{
# generate $UPGRADE_FILE
cat $SCRIPT_FILE > $UPGRADE_FILE
cat $TMP_UPGRADE_FILE >> $UPGRADE_FILE
rm $TMP_UPGRADE_FILE
# pad mangic to $UPGRADE_FILE
printf "%s" $MAGIC_STRING >> $UPGRADE_FILE
# pad $UPGRADE_FILE crc to $UPGRADE_FILE
#CRC_VALUE=`crc -a $SCRIPT_FILE | grep "CRC32" | awk '{print $3;}'`
#split -d -a 2 -b $SPILT_SIZE $SCRIPT_FILE $SCRIPT_FILE.
#printf "script file crc %s\n" $CRC_VALUE
#cat $SCRIPT_FILE.01 >> $UPGRADE_FILE
#rm -f $SCRIPT_FILE.*
#crc -a $UPGRADE_FILE
# copy the first 16 bytes to last
dd if=$UPGRADE_FILE of=./first16.bin bs=16 count=1;
cat ./first16.bin >> $UPGRADE_FILE
rm -f ./first16.bin
}
function parsing_para()
{
while [ $# != 0 ]; do
tmp1=$1
tmp2=`echo $1|cut -d= -f1`
case "$tmp2" in
"FullUpgrade" )
FullUpgrade=`echo $tmp1|cut -d= -f2`
;;
* )
echo "unknown parameter !!"
exit 1
;;
esac
shift
done
if [ "$FullUpgrade" == "Y" ];then
tmp=$FullUpgrade
else
read -p "Full Upgrade? (Y/n)" tmp
fi
}
#-----------------------------------------------
# Main():Generate Upgrade Image via Tftp Script
#-----------------------------------------------
IFS="
"
func_init;
func_process_main_script;
func_generate_script_file;
func_generate_upgrade_file;