diff --git a/Dockerfile b/Dockerfile index 66d9e078..8ebded93 100644 --- a/Dockerfile +++ b/Dockerfile @@ -102,7 +102,8 @@ RUN \ ubuntu-drivers-common \ xxd \ zip \ - zlib1g-dev && \ + zlib1g-dev \ + libsrt-openssl-dev && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* /tmp/cuda-keyring_1.1-1_all.deb @@ -329,7 +330,8 @@ RUN \ --extra-cflags="-march=native -fopenmp -I/usr/local/include/ -I/opt/intel/oneapi/ipp/latest/include/ipp/ -I/usr/local/cuda/include" \ --extra-ldflags="-fopenmp -L/usr/local/cuda/lib64 -L/usr/lib64 -L/usr/local/lib" \ --extra-libs='-lraisr -lstdc++ -lippcore -lippvm -lipps -lippi -lpthread -lm -lz -lbsd -lrdmacm -lbpf -lxdp' \ - --enable-cross-compile && \ + --enable-cross-compile \ + --enable-libsrt && \ make -j${nproc} COPY /gRPC /tmp/gRPC diff --git a/build.sh b/build.sh index 2f2241a1..47cab2ae 100755 --- a/build.sh +++ b/build.sh @@ -200,6 +200,7 @@ function install_dependencies { librdmacm-dev \ zlib1g-dev \ libelf-dev \ + libsrt-openssl-dev \ git \ cmake \ meson \ @@ -654,7 +655,8 @@ function ffmpeg_download_patch_build { --extra-cflags="-march=native -fopenmp -I${LOCAL_INSTALL_DEPENDENCIES_DIRECTORY}/vsr/install/include/ -I/opt/intel/oneapi/ipp/latest/include/ipp/ -I/usr/local/cuda/include" \ --extra-ldflags="-fopenmp -L${LOCAL_INSTALL_DEPENDENCIES_DIRECTORY}/vsr/install/lib -L/usr/local/cuda/lib64 -L/usr/lib64 -L/usr/local/lib" \ --extra-libs='-lraisr -lstdc++ -lippcore -lippvm -lipps -lippi -lpthread -lm -lz -lbsd -lrdmacm -lbpf -lxdp' \ - --enable-cross-compile && + --enable-cross-compile \ + --enable-libsrt && make -j"$(nproc)" && sudo make install) >>$log_file 2>&1; then echo diff --git a/gRPC/config_params.hpp b/gRPC/config_params.hpp index 7d34eb11..4e512633 100644 --- a/gRPC/config_params.hpp +++ b/gRPC/config_params.hpp @@ -56,6 +56,10 @@ struct MCM { std::string urn; }; +struct SRT { + std::string urn; +}; + enum payload_type { video = 0, audio @@ -70,7 +74,8 @@ struct Payload { enum stream_type { file = 0, st2110, - mcm + mcm, + srt }; struct StreamType { @@ -78,6 +83,7 @@ struct StreamType { File file; ST2110 st2110; MCM mcm; + SRT srt; }; struct Stream { diff --git a/gRPC/config_serialize_deserialize.hpp b/gRPC/config_serialize_deserialize.hpp index fa2c1ac2..588e7b40 100644 --- a/gRPC/config_serialize_deserialize.hpp +++ b/gRPC/config_serialize_deserialize.hpp @@ -12,8 +12,9 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Audio, channels, sample_rate, format, packet_ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(File, path, filename) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ST2110, network_interface, local_ip, remote_ip, transport, remote_port, payload_type) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(MCM, conn_type, transport, transport_pixel_format, ip, port, urn) +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SRT, urn) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Payload, type, video, audio) -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(StreamType, type, file, st2110, mcm) +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(StreamType, type, file, st2110, mcm, srt) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Stream, payload, stream_type) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Config, senders, receivers, function, multiviewer_columns, gpu_hw_acceleration, gpu_hw_acceleration_device, logging_level) diff --git a/gRPC/ffmpeg_pipeline_generator.cc b/gRPC/ffmpeg_pipeline_generator.cc index e59d2fed..259d0d97 100644 --- a/gRPC/ffmpeg_pipeline_generator.cc +++ b/gRPC/ffmpeg_pipeline_generator.cc @@ -191,6 +191,15 @@ int ffmpeg_append_stream_type(Stream &st, bool is_rx, int idx, std::string &pipe pipeline_string += " -"; } break; + case srt: + if (is_rx) { + pipeline_string += " -i "; + } + else { + pipeline_string += " -f mpegts "; + } + pipeline_string += s.srt.urn; + break; default: break; } @@ -199,7 +208,7 @@ int ffmpeg_append_stream_type(Stream &st, bool is_rx, int idx, std::string &pipe } int ffmpeg_combine_rx_tx(Stream &rx, Stream &tx, int idx, std::string &pipeline_string){ - if (ffmpeg_append_payload(rx.payload, pipeline_string) != 0) { + if ((rx.stream_type.type != srt) && ffmpeg_append_payload(rx.payload, pipeline_string) != 0) { pipeline_string.clear(); std::cout << "Error appending rx payload" << std::endl; return 1; @@ -234,7 +243,7 @@ int ffmpeg_append_multiviewer_input(Stream &s, int idx, std::string &pipeline_st return 1; } - if(ffmpeg_append_payload(s.payload, pipeline_string) != 0){ + if((s.stream_type.type != srt) && ffmpeg_append_payload(s.payload, pipeline_string) != 0){ pipeline_string.clear(); std::cout << "Error appending rx payload" << std::endl; return 1; @@ -386,7 +395,7 @@ int ffmpeg_append_recorder(Config &config, std::string &pipeline_string) { std::cout << "Error: recorder requires at least 2 senders" << std::endl; } - if (ffmpeg_append_payload(config.receivers[0].payload, pipeline_string) != 0){ + if ((config.receivers[0].stream_type.type != srt) && ffmpeg_append_payload(config.receivers[0].payload, pipeline_string) != 0){ pipeline_string.clear(); std::cout << "Error appending recorder rx payload" << std::endl; return 1; diff --git a/gRPC/unit_test/ffmpeg_pipeline_generator_test.cc b/gRPC/unit_test/ffmpeg_pipeline_generator_test.cc index 77245d3c..98e93dac 100644 --- a/gRPC/unit_test/ffmpeg_pipeline_generator_test.cc +++ b/gRPC/unit_test/ffmpeg_pipeline_generator_test.cc @@ -154,6 +154,32 @@ void fill_conf_receiver_mcm(Config &config) { } } +void fill_conf_receiver_srt(Config &config) { + config.function = "rx"; + config.gpu_hw_acceleration = "none"; + config.logging_level = 0; + + Payload p = get_video_payload_common(); + { + Stream s; + + s.payload = p; + s.stream_type.type = stream_type::srt; + s.stream_type.srt.urn = "srt://:20001?mode=caller"; + config.receivers.push_back(s); + } + + { + Stream s; + + s.payload = p; + s.stream_type.type = stream_type::file; + s.stream_type.file.path = "/home/test/recv"; + s.stream_type.file.filename = "1920x1080p10le_1.yuv"; + config.senders.push_back(s); + } +} + void fill_conf_multiviewer(Config &config) { config.function = "multiviewer"; config.gpu_hw_acceleration = "intel"; @@ -425,12 +451,25 @@ TEST(FFmpegPipelineGeneratorTest, test_mcm_receiver) { std::string pipeline_string; if (ffmpeg_generate_pipeline(conf, pipeline_string) != 0) { - ASSERT_EQ(1, 0) << "Error generating receiver pipeline" << std::endl; + ASSERT_EQ(1, 0) << "Error generating receiver mcm pipeline" << std::endl; } std::string expected_string = " -y -video_size 1920x1080 -pix_fmt yuv422p10le -r 30/1 -f rawvideo -f mcm -conn_type st2110 -transport st2110-20 -transport_pixel_format yuv422p10rfc4175 -ip_addr 192.168.96.10 -port 9002 -i \"0\" /home/test/recv/1920x1080p10le_1.yuv"; ASSERT_EQ(pipeline_string.compare(expected_string) == 0, 1) << "Expected: " << std::endl << expected_string << std::endl << " Got: " << std::endl << pipeline_string << std::endl; } +TEST(FFmpegPipelineGeneratorTest, test_srt) { + Config conf; + fill_conf_receiver_srt(conf); + + std::string pipeline_string; + + if (ffmpeg_generate_pipeline(conf, pipeline_string) != 0) { + ASSERT_EQ(1, 0) << "Error generating srt pipeline" << std::endl; + } + std::string expected_string = " -y -i srt://:20001?mode=caller /home/test/recv/1920x1080p10le_1.yuv"; + ASSERT_EQ(pipeline_string.compare(expected_string) == 0, 1) << "Expected: " << std::endl << expected_string << std::endl << " Got: " << std::endl << pipeline_string << std::endl; +} + TEST(FFmpegPipelineConfigTest, serialize_deserialize_multiviewer) { Config conf_reference; fill_conf_multiviewer(conf_reference); @@ -485,4 +524,35 @@ TEST(FFmpegPipelineConfigTest, serialize_deserialize_upscale) { ASSERT_EQ(pipeline_string_reference.compare(pipeline_string_deserialized) == 0, 1) << "Expected: " << std::endl << pipeline_string_reference << std::endl << " Got: " << std::endl << pipeline_string_deserialized << std::endl; -} \ No newline at end of file +} + +TEST(FFmpegPipelineConfigTest, serialize_deserialize_upscale_srt) { + Config conf_reference; + fill_conf_upscale(conf_reference); + + conf_reference.receivers[0].stream_type.type = stream_type::srt; + conf_reference.receivers[0].stream_type.srt.urn = "srt://:20001"; + + std::string pipeline_string_reference; + + if (ffmpeg_generate_pipeline(conf_reference, pipeline_string_reference) != 0) { + ASSERT_EQ(1, 0) << "Error generating convert pipeline" << std::endl; + } + + std::string json_conf_serialized; + if(serialize_config_json(conf_reference, json_conf_serialized) != 0) { + ASSERT_EQ(1, 0) << "Error serializing config" << std::endl; + } + + Config conf_deserialized; + std::string pipeline_string_deserialized; + if(deserialize_config_json(conf_deserialized, json_conf_serialized) != 0) { + ASSERT_EQ(1, 0) << "Error serializing config" << std::endl; + } + if (ffmpeg_generate_pipeline(conf_deserialized, pipeline_string_deserialized) != 0) { + ASSERT_EQ(1, 0) << "Error generating convert pipeline after deserialization" << std::endl; + } + + ASSERT_EQ(pipeline_string_reference.compare(pipeline_string_deserialized) == 0, 1) << "Expected: " << std::endl << pipeline_string_reference + << std::endl << " Got: " << std::endl << pipeline_string_deserialized << std::endl; +}