GStreamer + gst-rtsp-server(广电 / 酒店行业标准),本来以为在AI这么发达的情况下,小白搭建一个将udp/rtp转为rtsp的服务,应该不难,但实际上,都快被整疯的节奏。记录一下。
需求:由于iptv酒店项目需要多个机顶盒播出同步,而只有rtsp才可以的。故广电设备(比如编码器,卫星接收机输出的udp/rtp流)需要经过服务器转为rtsp流,基本就能同步播出的了。
由于自身能力有限,最终只能播出udp转的rtsp流。
推流软件:UdpTsAnalyser_1.61.exe,发送地址udp://239.94.0.31:5140,推送的广电常用的mpeg2格式的音视频流(ts流)。
环境搭建:
1.ubuntu20.04(太新太旧也是一堆错误);能正常运行后;地址为:192.168.11.212
2.进入/root/gst-build/gst-rtsp-server/examples目录:
vlc播放地址:rtsp://192.168.11.212:8554/test
(1)推本地流
./test-mp4 --port 8554 4.mp4
或者
./test-launch --port 8554 "filesrc location=4.mp4 ! qtdemux ! h264parse ! rtph264pay name=pay0 pt=96"
(2)udp不转码!直接封装:
**********udp不卡顿*****最终工业级无卡顿、超低延迟命令(推荐直接用这个) UDP-TS 转 RTSP
./test-launch --port 8554 \
"udpsrc port=5140 multicast-group=239.94.0.31 do-timestamp=false buffer-size=1048576 \
! tsparse set-timestamps=false \
! queue leaky=2 max-size-buffers=0 max-size-bytes=0 max-size-time=100000000 \
! rtpmp2tpay name=pay0 pt=96"
这个vlc播放是流畅的。
由于我们要播放多个节目,那我们重写test-launch.c的代码,root目录下建立my_rtsp_server目录:
1.频道地址配置文件:ch.conf
239.94.0.31:5140
239.94.0.32:5140
239.94.0.33:5140
239.94.0.34:5140
239.94.0.35:5140
239.94.0.36:5140
239.94.0.37:5140
239.94.0.38:5140
239.94.0.39:5140
239.94.0.40:5140
2.main.c文件,可以读取频道配置文件:
#include <gst/gst.h>
#include <gst/rtsp-server/rtsp-server.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define DEFAULT_RTSP_PORT "8554"
#define CHANNEL_FILE "ch.conf"static char *port = (char *)DEFAULT_RTSP_PORT;
static GOptionEntry entries[] = {
{"port", 'p', 0, G_OPTION_ARG_STRING, &port,
"RTSP server port (default: 8554)", "PORT"},
{NULL}
};typedef struct {
char ip[50];
int udp_port;
} Channel;int read_channels(Channel channels[], int max) {
FILE *f = fopen(CHANNEL_FILE, "r");
if (!f) {
g_printerr("Cannot open %s\n", CHANNEL_FILE);
return -1;
}int count = 0;
char line[128];while (fgets(line, sizeof(line), f) && count < max) {
memset(&channels[count], 0, sizeof(Channel));
char clean_line[128] = {0};
int j = 0;
for (int i = 0; line[i] != '\0'; i++) {
char c = line[i];
if ((c >= '0' && c <= '9') || c == '.' || c == ':') {
clean_line[j++] = c;
}
}if (strlen(clean_line) < 5) continue;
char *colon = strchr(clean_line, ':');
if (!colon) continue;*colon = 0;
strcpy(channels[count].ip, clean_line);
channels[count].udp_port = atoi(colon + 1);
count++;
}fclose(f);
return count;
}int main(int argc, char *argv[]) {
GMainLoop *loop;
GstRTSPServer *server;
GstRTSPMountPoints *mounts;
GOptionContext *optctx;
GError *error = NULL;Channel channels[20] = {0};
int channel_count, i;optctx = g_option_context_new("- UDP to RTSP Server");
g_option_context_add_main_entries(optctx, entries, NULL);
g_option_context_add_group(optctx, gst_init_get_option_group());
if (!g_option_context_parse(optctx, &argc, &argv, &error)) {
g_printerr("Option error: %s\n", error->message);
g_error_free(error);
return -1;
}
g_option_context_free(optctx);gst_init(&argc, &argv);
loop = g_main_loop_new(NULL, FALSE);server = gst_rtsp_server_new();
g_object_set(server, "service", port, NULL);
mounts = gst_rtsp_server_get_mount_points(server);channel_count = read_channels(channels, 20);
if (channel_count <= 0) {
g_printerr("No channels\n");
return -1;
}for (i = 0; i < channel_count; i++) {
char mount_path[128] = {0};
char pipeline[512] = {0};
GstRTSPMediaFactory *factory = gst_rtsp_media_factory_new();snprintf(mount_path, 127, "/iptv/%s:%d", channels[i].ip, channels[i].udp_port);
snprintf(pipeline, 511,
"udpsrc port=%d multicast-group=%s do-timestamp=false buffer-size=1048576 "
"! tsparse set-timestamps=false "
"! queue leaky=2 max-size-buffers=0 max-size-bytes=0 max-size-time=100000000 "
"! rtpmp2tpay name=pay0 pt=96",
channels[i].udp_port, channels[i].ip);gst_rtsp_media_factory_set_launch(factory, pipeline);
gst_rtsp_media_factory_set_shared(factory, TRUE);
gst_rtsp_media_factory_set_latency(factory, 0);
gst_rtsp_mount_points_add_factory(mounts, mount_path, factory);g_print("✅ OK: rtsp://0.0.0.0:%s%s\n", port, mount_path);
}g_object_unref(mounts);
gst_rtsp_server_attach(server, NULL);g_print("\n🚀 RTSP server running on port %s\n", port);
g_main_loop_run(loop);
return 0;
}
3.编译:
gcc main.c -o main `pkg-config --cflags --libs gstreamer-1.0 gstreamer-rtsp-server-1.0`
不报错,生成main执行文件即可
4.运行
./main
大概会显示:
root@linux:~/my_rtsp_server# ./main
? OK: rtsp://0.0.0.0:8554/iptv/239.94.0.31:5140
? OK: rtsp://0.0.0.0:8554/iptv/239.94.0.32:5140
? OK: rtsp://0.0.0.0:8554/iptv/239.94.0.33:5140
? OK: rtsp://0.0.0.0:8554/iptv/239.94.0.34:5140
? OK: rtsp://0.0.0.0:8554/iptv/239.94.0.35:5140
? OK: rtsp://0.0.0.0:8554/iptv/239.94.0.36:5140
? OK: rtsp://0.0.0.0:8554/iptv/239.94.0.37:5140
? OK: rtsp://0.0.0.0:8554/iptv/239.94.0.38:5140
? OK: rtsp://0.0.0.0:8554/iptv/239.94.0.39:5140
? OK: rtsp://0.0.0.0:8554/iptv/239.94.0.40:5140
? RTSP server running on port 8554
这就算正常的了,用vlc打开这些地址:
rtsp://192.168.11.212:8554/iptv/239.94.0.31:5140
rtsp://192.168.11.212:8554/iptv/239.94.0.32:5140
rtsp://192.168.11.212:8554/iptv/239.94.0.33:5140等,可以正常播放就可以了。