NDI入门教程二

一、移植到RK:

编译相关:
ndi本身没有什么好移植编译的,本身提供的就是so库。但是ndi依赖其它第三方开源库:
avahi; dbus; expat; libcap; libdameon。因为编译这些开源库的服务器也需要安装一些插件所以在自己虚拟机Ubuntu20.04上编译好so,再把so库打包到rootfs目录, 都是开源的读者可以自行下载对应版本就行编译。
目录结构:
 

xxx@xxx-VirtualBox:~/work/rk3588$ ls
avahi               build_spi_nand.sh  mkfirmware.sh                                     rockdev
build               docs               NDI_Advanced_SDK_v5_Linux                         tinyalsa_new
build_all.sh_bk     fdk-aac            note.sh                                           tools
build_avahi_all.sh  IMAGE              RK3588_LINUX_NVR_SDK_Release_V1.4.0_20221021.tgz  u-boot
build_emmc.sh       kernel             rkbin

交叉编译遇到很多问题,这里提供一键编译脚步,编译结果cp到rootfs相应目录:
build_avahi_all.sh 编译脚本:


#!/bin/sh

usage()
{
   echo "USAGE: [-A] [-D] [-E] [-C]  [-L] [-N] [-R]"
    echo "No ARGS means use default build option                  "
    echo "WHERE: -A = build avahi                                 "
    echo "       -D = build dbus                     "
    echo "       -E = build expat                                "
    echo "       -C = build libcap                               "
        echo "       -L = build libdaemon                             "
        echo "       -N = build ndi                             "
        echo "       -R = build libdaemon                             "
    exit 1
}

CODE_PATH=$PWD

BUILD_AVAHI=false
BUILD_DBUS=false
BUILD_EXPAT=false
BUILD_CAP=false
BUILD_DAEMON=false
BUILD_NDI=false
BUILD_CLEAN_FLAG=false

BUILD_JOBS=8
# check pass argument
while getopts "ADECLNR" arg
do
    case $arg in
        A)
            echo "will build avahi"
            BUILD_AVAHI=true
            ;;
        D)
            echo "will dbus"
            BUILD_DBUS=true
            ;;
        E)
            echo "will build expat"
            BUILD_EXPAT=true
            ;;
        C)
            echo "will build libcap"
            BUILD_CAP=true
            ;;
        L)
            echo "will build libdaemon"
            BUILD_DAEMON=true
            ;;
        N)
            echo "will build ndi"
            BUILD_NDI=true
            ;;                        
        R)
            echo "will clean"
            BUILD_CLEAN_FLAG=true
            ;;                        
        ?)
            usage ;;
    esac
done

# set env
echo "start set env.................."
declare -x PATH=$CODE_PATH/build//toolchain/bin/:$PATH
export PATH
declare -x CROSS_COMPILE="aarch64-none-linux-gnu-"
declare -x ARCH="arm64"
${CROSS_COMPILE}gcc -v
echo "end set env.................."

# build libdaemon-0.14
if [ "$BUILD_DAEMON" = true ] ; then
echo "start build libdaemon-0.14................."
if [ "$BUILD_CLEAN_FLAG" = true ] ; then
        echo "start clean && build libdaemon-0.14"
    cd avahi/libdaemon-0.14
        mkdir _install
        make clean
        ./configure \
        CC=aarch64-none-linux-gnu-gcc \
        CXX=aarch64-none-linux-gnu-g++ \
        --host=arm-none-linux \
        --prefix=$(pwd)/_install \
        ac_cv_func_setpgrp_void=yes
        make -j$BUILD_JOBS
        make install

else
        echo "start build libdaemon-0.14"
fi

if [ $? -eq 0 ]; then
    echo "Build libdaemon-0.14 ok!"
else
    echo "Build libdaemon-0.14 failed!"
    exit 1
fi
cd -
fi

# build libcap
if [ "$BUILD_CAP" = true ] ; then
echo "start build libcap-2.25................."
if [ "$BUILD_CLEAN_FLAG" = true ] ; then
        echo "start clean && build libcap"
    cd avahi/libcap-2.25
        mkdir _install
        make clean
        make -j$BUILD_JOBS
        make DESTDIR=$(pwd)/_install install

else
    cd avahi/libcap-2.25
        mkdir _install
        make -j$BUILD_JOBS
        make DESTDIR=$(pwd)/_install install
fi

if [ $? -eq 0 ]; then
    echo "Build libcap-2.25 ok!"
else
    echo "Build libcap-2.25 failed!"
    exit 1
fi
cd -
fi


# build expat
if [ "$BUILD_EXPAT" = true ] ; then
echo "start build expat-2.4.8................."
if [ "$BUILD_CLEAN_FLAG" = true ] ; then
        echo "start clean && build expat-2.4.8"
    cd avahi/expat-2.4.8
        mkdir _install
        ./configure \
        CC=aarch64-none-linux-gnu-gcc \
        CXX=aarch64-none-linux-gnu-g++ \
        --host=aarch64-none-linux \
        --prefix=$(pwd)/_install \
        ac_cv_func_setpgrp_void=yes\
        --enable-shared=no\
        --enable-static=yes
        make clean
        make -j$BUILD_JOBS
        make install

else
    cd avahi/expat-2.4.8
        mkdir _install
        ./configure \
        CC=aarch64-none-linux-gnu-gcc \
        CXX=aarch64-none-linux-gnu-g++ \
        --host=aarch64-none-linux \
        --prefix=$(pwd)/_install \
        ac_cv_func_setpgrp_void=yes\
        --enable-shared=no\
        --enable-static=yes
        make -j$BUILD_JOBS
        make install
fi

if [ $? -eq 0 ]; then
    echo "Build expat-2.4.8 ok!"
else
    echo "Build expat-2.4.8 failed!"
    exit 1
fi
cd -
fi


# build dbus-1.12.16
if [ "$BUILD_DBUS" = true ] ; then
echo "start build dbus-1.12.16................."
if [ "$BUILD_CLEAN_FLAG" = true ] ; then
        echo "start clean && build dbus-1.12.16"
    cd avahi/dbus-1.12.16
        mkdir _install
        make clean
        ./configure \
        CC=aarch64-none-linux-gnu-gcc \
        CXX=aarch64-none-linux-gnu-g++ \
        --host=aarch64-linux  \
        --enable-systemd=no \
        --enable-selinux=no \
        --with-x=no \
        --enable-tests=no \
        EXPAT_CFLAGS="-I$CODE_PATH/avahi/expat-2.4.8/_install/include" \
        EXPAT_LIBS="$CODE_PATH/avahi/expat-2.4.8/_install/lib/libexpat.a" \
        --with-session-socket-dir=/var/run/dbus \
        --with-system-socket=/var/run/dbus/system_bus_socket \
        --with-system-pid-file=/var/run/dbus/pid \
        --prefix=/usr/avahi/dbus-1.12.16/_install
        make -j$BUILD_JOBS
        make install

else
        echo "start build dbus-1.12.16"
fi
if [ $? -eq 0 ]; then
    echo "Build dbus-1.12.16 ok!"
else
    echo "Build dbus-1.12.16 failed!"
    exit 1
fi
cd -
fi


# build avahi
if [ "$BUILD_AVAHI" = true ] ; then
echo "start build avahi-0.8................."
if [ "$BUILD_CLEAN_FLAG" = true ] ; then
        echo "start clean && build avahi-0.8"
    cd avahi/avahi-0.8
        mkdir _install
        make clean
        ./configure \
        CC=aarch64-none-linux-gnu-gcc \
        CXX=aarch64-none-linux-gnu-g++ \
        --host=aarch64-none-linux-gnu \
        --with-xml=expat \
        --disable-qt3 \
        --disable-qt4 \
        --disable-qt5 \
        --disable-mono \
        --disable-libevent \
        --with-distro=none \
        --disable-glib \
        --disable-gobject \
        --disable-gtk \
        --disable-gtk3 \
        --disable-gdbm \
        --disable-python \
        --disable-python-dbus \
        CFLAGS="-I$CODE_PATH/avahi/expat-2.4.8/_install/include -I/usr/avahi/dbus-1.12.16/_install/include  -I$CODE_PATH/avahi/libcap-2.25/_install/usr/include" \
        LDFLAGS="-L/usr/avahi/dbus-1.12.16/_install/lib -L$CODE_PATH/avahi/expat-2.4.8/_install/lib  -L$CODE_PATH/avahi/libcap-2.25/_install/lib64" \
        LIBDAEMON_CFLAGS="-I$CODE_PATH/avahi/libdaemon-0.14/_install/include" \
        LIBDAEMON_LIBS="$CODE_PATH/avahi/libdaemon-0.14/_install/lib/libdaemon.a" \
        ac_cv_header_sys_capability_h=yes \
        --prefix=/usr/avahi/avahi-0.8/_install

        make -j$BUILD_JOBS
        make install

else
        echo "start build avahi-0.8"
fi
if [ $? -eq 0 ]; then
    echo "Build  avahi-0.8ok!"
else
    echo "Build avahi-0.8 failed!"
    exit 1
fi
cd -
fi

#buid ndi examples
if [ "$BUILD_NDI" = true ] ; then
echo "start build ndi................."
if [ "$BUILD_CLEAN_FLAG" = true ] ; then
        echo "start clean && build ndi"
        cd  NDI_Advanced_SDK_v5_Linux/examples/C++
        make NDILIB=aarch64-rockchip-linux-gnu CC=aarch64-none-linux-gnu-gcc CXX=aarch64-none-linux-gnu-g++ -j$BUILD_JOBS

else
        echo "build ndi"
fi

if [ $? -eq 0 ]; then
    echo "Build ndi ok!"
else
    echo "Build ndifailed!"
    exit 1
fi
cd -
fi


sync

mkdir -p build/rootfs/oem/lib
mkdir -p build/rootfs/oem/bin

# cp  libcap so
cp  avahi/libcap-2.25/_install/lib64/libcap.so.2.25 build/rootfs/oem/lib
cd build/rootfs/oem/lib
ln -s libcap.so.2.25 libcap.so.2
ln -s libcap.so.2.25 libcap.so
cd -
# cp  libdaemon so
cp avahi/libdaemon-0.14/_install/lib/libdaemon.so.0.5.0 build/rootfs/oem/lib
cd build/rootfs/oem/lib
ln -s libdaemon.so.0.5.0 libdaemon.so.0
ln -s libdaemon.so.0.5.0 libdaemon.so
cd -
# cp  libdbus so
cp avahi/dbus-1.12.16/_install/lib/libdbus-1.so.3.19.11 build/rootfs/oem/lib
cd build/rootfs/oem/lib
ln -s libdbus-1.so.3.19.11 libdbus-1.so.3
ln -s libdbus-1.so.3.19.11 libdbus-1.so
cd -
cp /usr/avahi/dbus-1.12.16/_install/bin/dbus-daemon build/rootfs/oem/bin

# cp  avahi so
cp avahi/avahi-0.8/_install/lib/libavahi-client.so.3.2.9 build/rootfs/oem/lib/
cp avahi/avahi-0.8/_install/lib/libavahi-common.so.3.5.3 build/rootfs/oem/lib/
cp avahi/avahi-0.8/_install/lib/libavahi-core.so.7.0.2 build/rootfs/oem/lib/
cd build/rootfs/oem/lib
ln -s libavahi-client.so.3.2.9 libavahi-client.so.3
ln -s libavahi-client.so.3.2.9 libavahi-client.so

ln -s libavahi-common.so.3.5.3 libavahi-common.so.3
ln -s libavahi-common.so.3.5.3 libavahi-common.so

ln -s libavahi-core.so.7.0.2 libavahi-core.so.7
ln -s libavahi-core.so.7.0.2 libavahi-core.so
cd -

cp /usr/avahi/avahi-0.8/_install/sbin/avahi-daemon build/rootfs/oem/bin

# cp  ndi sdk so
cp NDI_Advanced_SDK_v5_Linux/lib/aarch64-rockchip-linux-gnu/libndi.so.5.5.2  build/rootfs/oem/lib/
cd build/rootfs/oem/lib
ln -s libndi.so.5.5.2 libndi.so.5
ln -s libndi.so.5.5.2 libndi.so
cd -
cp NDI_Advanced_SDK_v5_Linux/examples/C++/NDIlib_Recv/NDIlib_Recv  build/rootfs/oem/bin/
cp NDI_Advanced_SDK_v5_Linux/examples/C++/NDIlib_Send_Video_and_Audio/NDIlib_Send_Video_and_Audio  build/rootfs/oem/bin/

cp /usr/avahi/avahi-0.8/_install/etc/dbus-1/system.d/avahi-dbus.conf /usr/avahi/dbus-1.12.16/_install/etc/dbus-1/system.conf
cp -rf /usr/avahi/ build/rootfs/usr/


sync

二、板端配置相关:

/etc/init.d/目录增加启动脚本S100_avahi:

#!/bin/sh

source /etc/profile.d/RkEnv.sh

echo "start avahi...................................."
/oem/bin/busybox adduser avahi -D -H
/oem/bin/busybox adduser messagebus -D -H
sync
cat /etc/group | grep avahi
if [ $? -eq 0 ]; then
    echo "Found!"
else
    echo "avahi:x:1001:" >> /etc/group
fi

export

sync
mkdir /var/run/dbus/ -p
/oem/bin/dbus-daemon --system --fork
/oem/bin/avahi-daemon &
#sleep 20 wait for net ready and system time ready.
sleep 20 && /oem/bin/ndi_send_h264_aac /oem/test.h264 /oem/qhc_48.wav &

RK3588 sdk bin目录自带的busybox 不带adduser 命令,需要自己下载重新编译一个。否则avahi和dbus跑不起来。
sleep 20的作用是等待网络获取到ip,以及系统时钟,avahi初始化。如果太早起来会失败,还有系统时间问题导致ndi so检测时间出错立马达到30分钟停止工作,免费版本只能使用30分钟。


三、NDI Demo使用:

普通版sdk裸数据发送:
windows打开 NDI 软件 -》点击 Studio Monitor -》Ubuntu 运行example的NDIlib_Send_Video_and_Audio -》在 Studio Monitor界面选择设备 -》windows看到画面和听到声音。
windows打开 NDI 软件 -》点击 Test Patterns -》Ubuntu 运行example的NDIlib_Send_Audio  -》看到打印信息。

四、高级版NDI Demo相关代码,开发测试程序:

背景:
  高级sdk只有一个发送demo,是基于数组的。
  我们最终是要发送h264和aac文件。需要编写一个读取aac,h264文件进行解码,解析,然后转换到ndi的数据结构再发送出去。
移植fdkaac开源库:
  这个比较简单网上很多。


编写发送h264,aac文件测试程序代码:
  代码路径:
  Z:\rk3588_linux_nvr\anker_3rdparty\NDI_Advanced_SDK_for_Linux\examples\C++_HX2\NDIlib_Send_H264
  编译:
#源码根目录 设置编译环境参数
CODE_PATH=$PWD
declare -x PATH=$CODE_PATH/build/toolchain/bin/:$PATH
export PATH
declare -x ARCH="arm64"
declare -x CROSS_COMPILE="aarch64-none-linux-gnu-"
#进入NDIlib_Send_H264目录编译
make -j8
  得到ndi_send_h264_aac ,运行:/oem/bin/ndi_send_h264_aac /oem/test.h264 /oem/qhc_48.wav &
  可以使用FFmpeg命令把mp4转成h264文件,如:
ffmpeg -i test.mp4 -codec copy -bsf: h264_mp4toannexb -f h264 test.h264
编写接收程序:
  代码位置:anker_3rdparty\NDI_Advanced_SDK_for_Linux\examples\C++_HX2\NDIlib_Recv_H264_AAC。
  高级sdk版本只有发送的demo,没有接收h264 aac的demo。只能自己看英文pdf和头文件去写 去试。
  遇到的问题:
  A. 接收的pcm数据保存成文件后,在audacity播放,声音不对,分析排查后发现ndi api接收到的audio frame的数据不是常用交错排列的pcm数据,而是先放channel_stride_in_bytes数据的通道1,再接着放channel_stride_in_bytes的通道2,以此类推,这是看头文件结构体猜,试出来的,英文pdf并没有介绍。
  B. 在自己虚拟机可以的程序,编译到rk3588 板子无法接收到音频数据。 通过排查分析和猜:编译器,运行环境等。把同样的代码在服务器编译测试现象一样。最后发现是ndi的so库会用dlopen方式加载FFmpeg相关的库去解码aac得到pcm数据。因为rk3588没有FFmpeg库所以导致ndi 库内部无法解码aac而且不会打印任何日志,导致我写的接收程序一直无法接收到音频数据。
  C. 因为存在B问题,而且我们不需要FFmpeg。接收端程序不是一定要接收pcm数据,可以接收aac数据然后用fdk-aac去解码得到pcm数据。查看pdf文档,可以设置参数直接接收aac数。但是接收到的数据保存文件无法在电脑上无法识别。通过分析发现接收到的数据没有adst头,手动添加adts头后电脑可以正确识别但是无法播放出声音。
  D. 分析无法播放出声音的问题。 通过dump数据和发送端对比,发现接收端接收到的audio frame数据比发送端多了44个字节+2字节。44字节不知道是ndi发送api加的还是接收api加的,2字节是发送端的extra data。保存成aac文件的时候去掉前面44字节和后面2字节的extra data即可,这样的aac文件就可以在电脑上播放了。
结合rk mpi,获取camera数据进行发送。camera -> venc -> ndi send。
  音频数据使用wav文件:
  ndi_send_camera_aac 3840 2160 60 /dev/video11 /oem/qhc_48.wav
  3840:x分辨率
  2160:y分辨率
  60: 帧率
  /dev/video11:camera设备节点命令
  /oem/qhc_48.wav: 要发送的wav文件

  音频数据使用声卡:
  ndi_send_camera_aac 3840 2160 60 /dev/video11
代码 rk3588_linux_nvr.git

六、测试:

ndi_send_camera_aac 程序发送4k 60帧 ,win10端接收预览,平均延时在150ms ~ 300ms。和画面变化有关和硬件编码器码率有关。

码率在1 ~ 6.5Mbps之间,和画面运动变化有关。

3. cpu使用率在1% ~5% 变化

内存:
开机后是82M,跑起ndi_send_camera_aac 后是338M, NDI库大概使用1M,大部分内存是RK MPI接口(camera,venc,isp)使用的。

  • 11
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
安装NDI SDK的教程如下: 1. 首先,你需要前往NDI SDK的官方网站下载完整的SDK。你可以在https://www.newtek.com/ndi/sdk/找到下载链接。点击下载链接,然后选择适合你操作系统的版本进行下载。 2. 下载完成后,解压缩SDK文件到你想要安装的目录。 3. 打开你的开发环境,比如Visual Studio等。 4. 在你的项目中,找到你的main函数所在的文件。 5. 在main函数的开头,添加以下代码来初始化NDI库: ```c++ if (!NDIlib_initialize()) return 0; ``` 这段代码会初始化NDI库,确保你的程序可以正常使用NDI功能。 6. 如果你需要使用NDI的发现功能,你可以在main函数中添加以下代码来创建一个NDI发现实例: ```c++ NDIlib_find_instance_t pNDI_find = NDIlib_find_create_v2(); if (!pNDI_find) return 0; ``` 这段代码会创建一个NDI发现实例,用于搜索和连接到NDI设备。 7. 如果你需要使用NDI的发送功能,你可以在main函数中添加以下代码来创建一个NDI发送实例: ```c++ NDIlib_send_instance_t pNDI_send = NDIlib_send_create(); if (!pNDI_send) return 0; ``` 这段代码会创建一个NDI发送实例,用于发送视频和音频数据。 8. 现在,你可以根据你的需求在main函数中继续编写你的代码,使用NDI SDK提供的功能。 请注意,以上代码只是示例,你需要根据你的具体情况进行适当的修改和调整。此外,为了正确使用NDI SDK,你还需要阅读SDK文档,并遵守SDK许可条款。 希望这个教程对你有帮助!如果你有任何其他问题,请随时提问。 #### 引用[.reference_title] - *1* [NDI技术实践与应用](https://blog.csdn.net/u014162133/article/details/103309780)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [ndi 推流拉流](https://blog.csdn.net/wangbuji/article/details/123012285)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值