Skip to content

Commit

Permalink
obs-ffmpeg: Fix SRT listener bug
Browse files Browse the repository at this point in the history
Fixes #10504.
There was a bug in FFmpeg implementation which was hidden by a bug in
libsrt; it was fixed in a recent commit [1].
When we ported FFmpeg libsrt.c to obs, we brought the said bug along.
When starting an SRT stream in listener mode, if no connection is made
by a client, there were two issues:
- 1) obs was stuck into a connecting loop,
- 2) the socket was not closed when exiting OBS.
This fixes the issue so that SRT is displaying that a stream started
when in listener mode even if NO client is connected.
This is the correct behaviour for a listener.
The stream now closes properly.

[1] https://git.videolan.org/?p=ffmpeg.git;a=commit;h=87677c2195e86b126c3438439a05d0a46ae5bb50
Signed-off-by: pkv <pkv@obsproject.com>
  • Loading branch information
pkviet authored and tt2468 committed Aug 10, 2024
1 parent e8f87e4 commit 1451554
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 32 deletions.
44 changes: 21 additions & 23 deletions plugins/obs-ffmpeg/obs-ffmpeg-mpegts.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,14 @@ void ffmpeg_mpegts_log_error(int log_level, struct ffmpeg_data *data,
blog(log_level, "%s", out);
}

static bool is_rist(struct ffmpeg_output *stream)
static bool is_rist(const char *url)
{
return !strncmp(stream->ff_data.config.url, RIST_PROTO,
sizeof(RIST_PROTO) - 1);
return !strncmp(url, RIST_PROTO, sizeof(RIST_PROTO) - 1);
}

static bool is_srt(struct ffmpeg_output *stream)
static bool is_srt(const char *url)
{
return !strncmp(stream->ff_data.config.url, SRT_PROTO,
sizeof(SRT_PROTO) - 1);
return !strncmp(url, SRT_PROTO, sizeof(SRT_PROTO) - 1);
}

static bool proto_is_allowed(struct ffmpeg_output *stream)
Expand Down Expand Up @@ -467,8 +465,8 @@ static inline int open_output_file(struct ffmpeg_output *stream,
struct ffmpeg_data *data)
{
int ret;
bool rist = is_rist(stream);
bool srt = is_srt(stream);
bool rist = data->config.is_rist;
bool srt = data->config.is_srt;
bool allowed_proto = proto_is_allowed(stream);
AVDictionary *dict = NULL;

Expand Down Expand Up @@ -591,10 +589,7 @@ static void close_audio(struct ffmpeg_data *data)
static void close_mpegts_url(struct ffmpeg_output *stream, bool is_rist)
{
int err = 0;
AVIOContext *s = stream->s;
if (!s)
return;
URLContext *h = s->opaque;
URLContext *h = stream->h;
if (!h)
return; /* can happen when opening the url fails */

Expand All @@ -608,10 +603,14 @@ static void close_mpegts_url(struct ffmpeg_output *stream, bool is_rist)
av_freep(h);

/* close custom avio_context for srt or rist */
avio_flush(stream->s);
stream->s->opaque = NULL;
av_freep(&stream->s->buffer);
avio_context_free(&stream->s);
AVIOContext *s = stream->s;
if (!s)
return;

avio_flush(s);
s->opaque = NULL;
av_freep(&s->buffer);
avio_context_free(&s);

if (err)
info("[ffmpeg mpegts muxer]: Error closing URL %s",
Expand All @@ -632,8 +631,8 @@ void ffmpeg_mpegts_data_free(struct ffmpeg_output *stream,
}

if (data->output) {
if (is_rist(stream) || is_srt(stream)) {
close_mpegts_url(stream, is_rist(stream));
if (data->config.is_rist || data->config.is_srt) {
close_mpegts_url(stream, data->config.is_rist);
} else {
avio_close(data->output->pb);
}
Expand Down Expand Up @@ -757,11 +756,10 @@ static void ffmpeg_mpegts_destroy(void *data)
struct ffmpeg_output *output = data;

if (output) {
ffmpeg_mpegts_full_stop(output);
if (output->connecting)
pthread_join(output->start_thread, NULL);

ffmpeg_mpegts_full_stop(output);

pthread_mutex_destroy(&output->write_mutex);
os_sem_destroy(output->write_sem);
os_event_destroy(output->stop_event);
Expand Down Expand Up @@ -910,7 +908,8 @@ static bool set_config(struct ffmpeg_output *stream)
service, OBS_SERVICE_CONNECT_INFO_ENCRYPT_PASSPHRASE);
config.format_name = "mpegts";
config.format_mime_type = "video/M2PT";

config.is_rist = is_rist(config.url);
config.is_srt = is_srt(config.url);
/* 2. video settings */

// 2.a) set width & height
Expand Down Expand Up @@ -1110,6 +1109,7 @@ static void ffmpeg_mpegts_full_stop(void *data)
obs_output_end_data_capture(output->output);
ffmpeg_mpegts_deactivate(output);
}
ffmpeg_mpegts_data_free(output, &output->ff_data);
}

static void ffmpeg_mpegts_stop(void *data, uint64_t ts)
Expand Down Expand Up @@ -1144,8 +1144,6 @@ static void ffmpeg_mpegts_deactivate(struct ffmpeg_output *output)
da_free(output->packets);

pthread_mutex_unlock(&output->write_mutex);

ffmpeg_mpegts_data_free(output, &output->ff_data);
}

static uint64_t ffmpeg_mpegts_total_bytes(void *data)
Expand Down
2 changes: 2 additions & 0 deletions plugins/obs-ffmpeg/obs-ffmpeg-output.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ struct ffmpeg_cfg {
const char *password;
const char *stream_id;
const char *encrypt_passphrase;
bool is_srt;
bool is_rist;
};

struct ffmpeg_audio_info {
Expand Down
23 changes: 14 additions & 9 deletions plugins/obs-ffmpeg/obs-ffmpeg-srt.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,15 @@ static int libsrt_network_wait_fd(URLContext *h, int eid, int write)
int ret, len = 1, errlen = 1;
SRTSOCKET ready[1];
SRTSOCKET error[1];

SRTContext *s = (SRTContext *)h->priv_data;
if (write) {
ret = srt_epoll_wait(eid, error, &errlen, ready, &len,
POLLING_TIME, 0, 0, 0, 0);
} else {
ret = srt_epoll_wait(eid, ready, &len, error, &errlen,
POLLING_TIME, 0, 0, 0, 0);
}
if (len == 1 && errlen == 1) {
if (len == 1 && errlen == 1 && s->mode == SRT_MODE_CALLER) {
/* Socket reported in wsock AND rsock signifies an error. */
int reason = srt_getrejectreason(*ready);

Expand Down Expand Up @@ -232,7 +232,7 @@ static int libsrt_listen(int eid, SRTSOCKET fd, const struct sockaddr *addr,
if (srt_listen(fd, 1))
return libsrt_neterrno(h);

ret = libsrt_network_wait_fd_timeout(h, eid, 1, timeout,
ret = libsrt_network_wait_fd_timeout(h, eid, 0, timeout,
&h->interrupt_callback);
if (ret < 0)
return ret;
Expand Down Expand Up @@ -462,7 +462,7 @@ static int libsrt_setup(URLContext *h, const char *uri)
char hostname[1024], proto[1024], path[1024];
char portstr[10];
int64_t open_timeout = 0;
int eid, write_eid;
int eid;
struct sockaddr_in la;

av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
Expand Down Expand Up @@ -552,20 +552,23 @@ static int libsrt_setup(URLContext *h, const char *uri)
blog(LOG_DEBUG,
"[obs-ffmpeg mpegts muxer / libsrt]: libsrt_socket_nonblock failed");

ret = write_eid = libsrt_epoll_create(h, fd, 1);
if (ret < 0)
goto fail1;
if (s->mode == SRT_MODE_LISTENER) {
int read_eid = ret = libsrt_epoll_create(h, fd, 0);
if (ret < 0)
goto fail1;
// multi-client
ret = libsrt_listen(write_eid, fd, cur_ai->ai_addr,
ret = libsrt_listen(read_eid, fd, cur_ai->ai_addr,
(socklen_t)cur_ai->ai_addrlen, h,
s->listen_timeout);
srt_epoll_release(write_eid);
srt_epoll_release(read_eid);
if (ret < 0)
goto fail1;
srt_close(fd);
fd = ret;
} else {
int write_eid = ret = libsrt_epoll_create(h, fd, 1);
if (ret < 0)
goto fail1;
if (s->mode == SRT_MODE_RENDEZVOUS) {
if (srt_bind(fd, (struct sockaddr *)&la,
sizeof(struct sockaddr_in))) {
Expand Down Expand Up @@ -878,6 +881,8 @@ static int libsrt_write(URLContext *h, const uint8_t *buf, int size)
static int libsrt_close(URLContext *h)
{
SRTContext *s = (SRTContext *)h->priv_data;
if (!s)
return 0;
if (s->streamid)
av_freep(&s->streamid);
if (s->passphrase)
Expand Down

0 comments on commit 1451554

Please sign in to comment.