mirror of
https://github.com/Genymobile/scrcpy.git
synced 2026-04-21 01:33:36 +00:00
Rename --stream-port to --srt-sink (SRT protocol), fix video/audio assertion with --no-playback
Co-authored-by: yeicor <4929005+yeicor@users.noreply.github.com>
This commit is contained in:
parent
2fcba7e5b3
commit
eb585c2c4f
6 changed files with 59 additions and 39 deletions
|
|
@ -114,7 +114,7 @@ enum {
|
|||
OPT_NO_VD_SYSTEM_DECORATIONS,
|
||||
OPT_NO_VD_DESTROY_CONTENT,
|
||||
OPT_DISPLAY_IME_POLICY,
|
||||
OPT_STREAM_PORT,
|
||||
OPT_SRT_SINK,
|
||||
};
|
||||
|
||||
struct sc_option {
|
||||
|
|
@ -958,13 +958,17 @@ static const struct sc_option options[] = {
|
|||
#endif
|
||||
},
|
||||
{
|
||||
.longopt_id = OPT_STREAM_PORT,
|
||||
.longopt = "stream-port",
|
||||
.argdesc = "port",
|
||||
.text = "Start a TCP server that streams the device video (and audio, "
|
||||
"if enabled) as MPEG-TS on the given port. "
|
||||
"Once started, connect with any compatible player using "
|
||||
"tcp://127.0.0.1:<port> (e.g. in OBS Media Source or VLC).",
|
||||
.longopt_id = OPT_SRT_SINK,
|
||||
.longopt = "srt-sink",
|
||||
.argdesc = "url",
|
||||
.text = "Stream the device video (and audio, if enabled) as MPEG-TS "
|
||||
"over SRT to the given URL.\n"
|
||||
"Example: srt://0.0.0.0:8080\n"
|
||||
"scrcpy acts as the SRT listener (server) by default; "
|
||||
"?mode=listener is appended automatically if not present.\n"
|
||||
"Connect with any SRT-compatible player, e.g.:\n"
|
||||
" VLC: srt://127.0.0.1:8080\n"
|
||||
" ffplay: -i srt://127.0.0.1:8080",
|
||||
},
|
||||
{
|
||||
.longopt_id = OPT_V4L2_SINK,
|
||||
|
|
@ -2696,10 +2700,8 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||
LOGE("OTG mode (--otg) is disabled.");
|
||||
return false;
|
||||
#endif
|
||||
case OPT_STREAM_PORT:
|
||||
if (!parse_port(optarg, &opts->stream_port)) {
|
||||
return false;
|
||||
}
|
||||
case OPT_SRT_SINK:
|
||||
opts->srt_sink = optarg;
|
||||
break;
|
||||
case OPT_V4L2_SINK:
|
||||
#ifdef HAVE_V4L2
|
||||
|
|
@ -2891,13 +2893,15 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||
}
|
||||
|
||||
if (opts->video && !opts->video_playback && !opts->record_filename
|
||||
&& !v4l2) {
|
||||
LOGI("No video playback, no recording, no V4L2 sink: video disabled");
|
||||
&& !v4l2 && !opts->srt_sink) {
|
||||
LOGI("No video playback, no recording, no V4L2 sink, no SRT sink: "
|
||||
"video disabled");
|
||||
opts->video = false;
|
||||
}
|
||||
|
||||
if (opts->audio && !opts->audio_playback && !opts->record_filename) {
|
||||
LOGI("No audio playback, no recording: audio disabled");
|
||||
if (opts->audio && !opts->audio_playback && !opts->record_filename
|
||||
&& !opts->srt_sink) {
|
||||
LOGI("No audio playback, no recording, no SRT sink: audio disabled");
|
||||
opts->audio = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ const struct scrcpy_options scrcpy_options_default = {
|
|||
.v4l2_device = NULL,
|
||||
.v4l2_buffer = 0,
|
||||
#endif
|
||||
.stream_port = 0,
|
||||
.srt_sink = NULL,
|
||||
#ifdef HAVE_USB
|
||||
.otg = false,
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ struct scrcpy_options {
|
|||
const char *v4l2_device;
|
||||
sc_tick v4l2_buffer;
|
||||
#endif
|
||||
uint16_t stream_port; // 0 means disabled
|
||||
const char *srt_sink;
|
||||
#ifdef HAVE_USB
|
||||
bool otg;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -636,8 +636,8 @@ scrcpy(struct scrcpy_options *options) {
|
|||
}
|
||||
}
|
||||
|
||||
if (options->stream_port) {
|
||||
if (!sc_stream_sink_init(&s->stream_sink, options->stream_port,
|
||||
if (options->srt_sink) {
|
||||
if (!sc_stream_sink_init(&s->stream_sink, options->srt_sink,
|
||||
options->video, options->audio)) {
|
||||
goto end;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -181,26 +181,37 @@ sc_stream_sink_process_header(struct sc_stream_sink *sink) {
|
|||
}
|
||||
|
||||
{
|
||||
// Open the TCP server: this blocks until a client connects (or
|
||||
// sink->stopped is set, via the interrupt callback)
|
||||
char url[64];
|
||||
snprintf(url, sizeof(url),
|
||||
"tcp://0.0.0.0:%" PRIu16 "?listen=1", sink->port);
|
||||
// Build the SRT listener URL. If the user already specified
|
||||
// mode=, use the URL as-is; otherwise append ?mode=listener
|
||||
// so that scrcpy acts as the SRT server waiting for a player.
|
||||
const char *connect_url = sink->url;
|
||||
char *alloc_url = NULL;
|
||||
if (!strstr(sink->url, "mode=")) {
|
||||
const char *sep = strchr(sink->url, '?') ? "&" : "?";
|
||||
const char *suffix = "mode=listener";
|
||||
size_t len = strlen(sink->url) + strlen(sep) + strlen(suffix) + 1;
|
||||
alloc_url = malloc(len);
|
||||
if (!alloc_url) {
|
||||
LOG_OOM();
|
||||
goto end;
|
||||
}
|
||||
snprintf(alloc_url, len, "%s%s%s", sink->url, sep, suffix);
|
||||
connect_url = alloc_url;
|
||||
}
|
||||
|
||||
AVIOInterruptCB int_cb = {
|
||||
.callback = sc_stream_sink_interrupt_cb,
|
||||
.opaque = sink,
|
||||
};
|
||||
|
||||
LOGI("Stream sink: waiting for client on tcp://127.0.0.1:%" PRIu16,
|
||||
sink->port);
|
||||
LOGI("SRT sink: waiting for client on %s", sink->url);
|
||||
|
||||
int r = avio_open2(&sink->ctx->pb, url, AVIO_FLAG_WRITE,
|
||||
int r = avio_open2(&sink->ctx->pb, connect_url, AVIO_FLAG_WRITE,
|
||||
&int_cb, NULL);
|
||||
free(alloc_url);
|
||||
if (r < 0) {
|
||||
if (!sink->stopped) {
|
||||
LOGE("Failed to open stream server on port %" PRIu16,
|
||||
sink->port);
|
||||
LOGE("Failed to open SRT server on %s", sink->url);
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
|
|
@ -238,8 +249,7 @@ sc_stream_sink_process_packets(struct sc_stream_sink *sink) {
|
|||
return false;
|
||||
}
|
||||
|
||||
LOGI("Stream sink: streaming started on tcp://127.0.0.1:%" PRIu16,
|
||||
sink->port);
|
||||
LOGI("SRT sink: streaming started on %s", sink->url);
|
||||
|
||||
AVPacket *video_pkt = NULL;
|
||||
AVPacket *audio_pkt = NULL;
|
||||
|
|
@ -635,17 +645,21 @@ sc_stream_sink_audio_packet_sink_disable(struct sc_packet_sink *sink) {
|
|||
}
|
||||
|
||||
bool
|
||||
sc_stream_sink_init(struct sc_stream_sink *sink, uint16_t port,
|
||||
sc_stream_sink_init(struct sc_stream_sink *sink, const char *url,
|
||||
bool video, bool audio) {
|
||||
assert(video || audio);
|
||||
|
||||
sink->port = port;
|
||||
sink->url = strdup(url);
|
||||
if (!sink->url) {
|
||||
LOG_OOM();
|
||||
return false;
|
||||
}
|
||||
sink->video = video;
|
||||
sink->audio = audio;
|
||||
|
||||
bool ok = sc_mutex_init(&sink->mutex);
|
||||
if (!ok) {
|
||||
return false;
|
||||
goto error_url_free;
|
||||
}
|
||||
|
||||
ok = sc_cond_init(&sink->cond);
|
||||
|
|
@ -666,7 +680,7 @@ sc_stream_sink_init(struct sc_stream_sink *sink, uint16_t port,
|
|||
sc_stream_sink_stream_init(&sink->video_stream);
|
||||
sc_stream_sink_stream_init(&sink->audio_stream);
|
||||
|
||||
// Allocate the output format context with mpegts (ideal for TCP streaming)
|
||||
// Allocate the output format context with mpegts (for network streaming)
|
||||
const AVOutputFormat *oformat = av_guess_format("mpegts", NULL, NULL);
|
||||
if (!oformat) {
|
||||
LOGE("Could not find mpegts muxer");
|
||||
|
|
@ -712,6 +726,8 @@ error_cond_destroy:
|
|||
sc_cond_destroy(&sink->cond);
|
||||
error_mutex_destroy:
|
||||
sc_mutex_destroy(&sink->mutex);
|
||||
error_url_free:
|
||||
free(sink->url);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -746,4 +762,5 @@ sc_stream_sink_destroy(struct sc_stream_sink *sink) {
|
|||
sc_cond_destroy(&sink->cond);
|
||||
sc_mutex_destroy(&sink->mutex);
|
||||
avformat_free_context(sink->ctx);
|
||||
free(sink->url);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
#include "common.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <libavcodec/packet.h>
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
|
|
@ -34,7 +33,7 @@ struct sc_stream_sink {
|
|||
bool audio;
|
||||
bool video;
|
||||
|
||||
uint16_t port;
|
||||
char *url;
|
||||
|
||||
AVFormatContext *ctx;
|
||||
|
||||
|
|
@ -57,7 +56,7 @@ struct sc_stream_sink {
|
|||
};
|
||||
|
||||
bool
|
||||
sc_stream_sink_init(struct sc_stream_sink *sink, uint16_t port,
|
||||
sc_stream_sink_init(struct sc_stream_sink *sink, const char *url,
|
||||
bool video, bool audio);
|
||||
|
||||
bool
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue