Skip to content

Commit

Permalink
Add --no-video
Browse files Browse the repository at this point in the history
Similar to --no-audio, add --no-video to play audio only.

Fixes #3842 <#3842>
PR #3978 <#3978>
  • Loading branch information
rom1v committed May 8, 2023
1 parent e89e772 commit 8c650e5
Show file tree
Hide file tree
Showing 17 changed files with 243 additions and 96 deletions.
1 change: 1 addition & 0 deletions app/data/bash-completion/scrcpy
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ _scrcpy() {
--no-key-repeat
--no-mipmaps
--no-power-on
--no-video
--otg
-p --port=
--power-off-on-close
Expand Down
1 change: 1 addition & 0 deletions app/data/zsh-completion/_scrcpy
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ arguments=(
'--no-key-repeat[Do not forward repeated key events when a key is held down]'
'--no-mipmaps[Disable the generation of mipmaps]'
'--no-power-on[Do not power on the device on start]'
'--no-video[Disable video forwarding]'
'--otg[Run in OTG mode \(simulating physical keyboard and mouse\)]'
{-p,--port=}'[\[port\[\:port\]\] Set the TCP port \(range\) used by the client to listen]'
'--power-off-on-close[Turn the device screen off when closing scrcpy]'
Expand Down
4 changes: 4 additions & 0 deletions app/scrcpy.1
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@ If the renderer is OpenGL 3.0+ or OpenGL ES 2.0+, then mipmaps are automatically
.B \-\-no\-power\-on
Do not power on the device on start.

.TP
.B \-\-no\-video
Disable video forwarding.

.TP
.B \-\-otg
Run in OTG mode: simulate physical keyboard and mouse, as if the computer keyboard and mouse were plugged directly to the device via an OTG cable.
Expand Down
21 changes: 18 additions & 3 deletions app/src/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ enum {
OPT_AUDIO_BUFFER,
OPT_AUDIO_OUTPUT_BUFFER,
OPT_NO_DISPLAY,
OPT_NO_VIDEO,
};

struct sc_option {
Expand Down Expand Up @@ -407,6 +408,11 @@ static const struct sc_option options[] = {
.longopt = "no-power-on",
.text = "Do not power on the device on start.",
},
{
.longopt_id = OPT_NO_VIDEO,
.longopt = "no-video",
.text = "Disable video forwarding.",
},
{
.longopt_id = OPT_OTG,
.longopt = "otg",
Expand Down Expand Up @@ -1797,6 +1803,9 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
case OPT_NO_DOWNSIZE_ON_ERROR:
opts->downsize_on_error = false;
break;
case OPT_NO_VIDEO:
opts->video = false;
break;
case OPT_NO_AUDIO:
opts->audio = false;
break;
Expand Down Expand Up @@ -2042,14 +2051,20 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
#endif

#ifdef HAVE_USB
if (!opts->mirror && opts->control && !opts->otg) {
if (!(opts->mirror && opts->video) && !opts->otg) {
#else
if (!opts->mirror && opts->control) {
if (!(opts->mirror && opts->video)) {
#endif
LOGD("Mirroring is disabled, force --no-control");
// If video mirroring is disabled and OTG are disabled, then there is
// no way to control the device.
opts->control = false;
}

if (!opts->video) {
// If video is disabled, then scrcpy must exit on audio failure.
opts->require_audio = true;
}

return true;
}

Expand Down
1 change: 1 addition & 0 deletions app/src/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ const struct scrcpy_options scrcpy_options_default = {
.cleanup = true,
.start_fps_counter = false,
.power_on = true,
.video = true,
.audio = true,
.require_audio = false,
.list_encoders = false,
Expand Down
1 change: 1 addition & 0 deletions app/src/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ struct scrcpy_options {
bool cleanup;
bool start_fps_counter;
bool power_on;
bool video;
bool audio;
bool require_audio;
bool list_encoders;
Expand Down
69 changes: 45 additions & 24 deletions app/src/recorder.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ sc_recorder_close_output_file(struct sc_recorder *recorder) {

static inline bool
sc_recorder_has_empty_queues(struct sc_recorder *recorder) {
if (sc_vecdeque_is_empty(&recorder->video_queue)) {
if (recorder->video && sc_vecdeque_is_empty(&recorder->video_queue)) {
// The video queue is empty
return true;
}
Expand All @@ -176,15 +176,19 @@ sc_recorder_process_header(struct sc_recorder *recorder) {
sc_cond_wait(&recorder->stream_cond, &recorder->mutex);
}

if (sc_vecdeque_is_empty(&recorder->video_queue)) {
if (recorder->video && sc_vecdeque_is_empty(&recorder->video_queue)) {
assert(recorder->stopped);
// If the recorder is stopped, don't process anything if there are not
// at least video packets
sc_mutex_unlock(&recorder->mutex);
return false;
}

AVPacket *video_pkt = sc_vecdeque_pop(&recorder->video_queue);
AVPacket *video_pkt = NULL;
if (!sc_vecdeque_is_empty(&recorder->video_queue)) {
assert(recorder->video);
video_pkt = sc_vecdeque_pop(&recorder->video_queue);
}

AVPacket *audio_pkt = NULL;
if (!sc_vecdeque_is_empty(&recorder->audio_queue)) {
Expand All @@ -196,17 +200,19 @@ sc_recorder_process_header(struct sc_recorder *recorder) {

int ret = false;

if (video_pkt->pts != AV_NOPTS_VALUE) {
LOGE("The first video packet is not a config packet");
goto end;
}
if (video_pkt) {
if (video_pkt->pts != AV_NOPTS_VALUE) {
LOGE("The first video packet is not a config packet");
goto end;
}

assert(recorder->video_stream_index >= 0);
AVStream *video_stream =
recorder->ctx->streams[recorder->video_stream_index];
bool ok = sc_recorder_set_extradata(video_stream, video_pkt);
if (!ok) {
goto end;
assert(recorder->video_stream_index >= 0);
AVStream *video_stream =
recorder->ctx->streams[recorder->video_stream_index];
bool ok = sc_recorder_set_extradata(video_stream, video_pkt);
if (!ok) {
goto end;
}
}

if (audio_pkt) {
Expand All @@ -218,13 +224,13 @@ sc_recorder_process_header(struct sc_recorder *recorder) {
assert(recorder->audio_stream_index >= 0);
AVStream *audio_stream =
recorder->ctx->streams[recorder->audio_stream_index];
ok = sc_recorder_set_extradata(audio_stream, audio_pkt);
bool ok = sc_recorder_set_extradata(audio_stream, audio_pkt);
if (!ok) {
goto end;
}
}

ok = avformat_write_header(recorder->ctx, NULL) >= 0;
bool ok = avformat_write_header(recorder->ctx, NULL) >= 0;
if (!ok) {
LOGE("Failed to write header to %s", recorder->filename);
goto end;
Expand All @@ -233,7 +239,9 @@ sc_recorder_process_header(struct sc_recorder *recorder) {
ret = true;

end:
av_packet_free(&video_pkt);
if (video_pkt) {
av_packet_free(&video_pkt);
}
if (audio_pkt) {
av_packet_free(&audio_pkt);
}
Expand Down Expand Up @@ -263,7 +271,8 @@ sc_recorder_process_packets(struct sc_recorder *recorder) {
sc_mutex_lock(&recorder->mutex);

while (!recorder->stopped) {
if (!video_pkt && !sc_vecdeque_is_empty(&recorder->video_queue)) {
if (recorder->video && !video_pkt &&
!sc_vecdeque_is_empty(&recorder->video_queue)) {
// A new packet may be assigned to video_pkt and be processed
break;
}
Expand All @@ -278,6 +287,11 @@ sc_recorder_process_packets(struct sc_recorder *recorder) {
// If stopped is set, continue to process the remaining events (to
// finish the recording) before actually stopping.

// If there is no video, then the video_queue will remain empty forever
// and video_pkt will always be NULL.
assert(recorder->video || (!video_pkt
&& sc_vecdeque_is_empty(&recorder->video_queue)));

// If there is no audio, then the audio_queue will remain empty forever
// and audio_pkt will always be NULL.
assert(recorder->audio || (!audio_pkt
Expand Down Expand Up @@ -319,6 +333,9 @@ sc_recorder_process_packets(struct sc_recorder *recorder) {
if (!recorder->audio) {
assert(video_pkt);
pts_origin = video_pkt->pts;
} else if (!recorder->video) {
assert(audio_pkt);
pts_origin = audio_pkt->pts;
} else if (video_pkt && audio_pkt) {
pts_origin = MIN(video_pkt->pts, audio_pkt->pts);
} else if (recorder->stopped) {
Expand Down Expand Up @@ -639,7 +656,7 @@ sc_recorder_audio_packet_sink_disable(struct sc_packet_sink *sink) {

bool
sc_recorder_init(struct sc_recorder *recorder, const char *filename,
enum sc_record_format format, bool audio,
enum sc_record_format format, bool video, bool audio,
const struct sc_recorder_callbacks *cbs, void *cbs_userdata) {
recorder->filename = strdup(filename);
if (!recorder->filename) {
Expand All @@ -662,6 +679,8 @@ sc_recorder_init(struct sc_recorder *recorder, const char *filename,
goto error_queue_cond_destroy;
}

assert(video || audio);
recorder->video = video;
recorder->audio = audio;

sc_vecdeque_init(&recorder->video_queue);
Expand All @@ -680,13 +699,15 @@ sc_recorder_init(struct sc_recorder *recorder, const char *filename,
recorder->cbs = cbs;
recorder->cbs_userdata = cbs_userdata;

static const struct sc_packet_sink_ops video_ops = {
.open = sc_recorder_video_packet_sink_open,
.close = sc_recorder_video_packet_sink_close,
.push = sc_recorder_video_packet_sink_push,
};
if (video) {
static const struct sc_packet_sink_ops video_ops = {
.open = sc_recorder_video_packet_sink_open,
.close = sc_recorder_video_packet_sink_close,
.push = sc_recorder_video_packet_sink_push,
};

recorder->video_packet_sink.ops = &video_ops;
recorder->video_packet_sink.ops = &video_ops;
}

if (audio) {
static const struct sc_packet_sink_ops audio_ops = {
Expand Down
3 changes: 2 additions & 1 deletion app/src/recorder.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ struct sc_recorder {
* may access it without data races.
*/
bool audio;
bool video;

char *filename;
enum sc_record_format format;
Expand Down Expand Up @@ -59,7 +60,7 @@ struct sc_recorder_callbacks {

bool
sc_recorder_init(struct sc_recorder *recorder, const char *filename,
enum sc_record_format format, bool audio,
enum sc_record_format format, bool video, bool audio,
const struct sc_recorder_callbacks *cbs, void *cbs_userdata);

bool
Expand Down
54 changes: 32 additions & 22 deletions app/src/scrcpy.c
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ scrcpy(struct scrcpy_options *options) {
.lock_video_orientation = options->lock_video_orientation,
.control = options->control,
.display_id = options->display_id,
.video = options->video,
.audio = options->audio,
.show_touches = options->show_touches,
.stay_awake = options->stay_awake,
Expand Down Expand Up @@ -389,7 +390,7 @@ scrcpy(struct scrcpy_options *options) {
sdl_set_hints(options->render_driver);

// Initialize SDL video and audio in addition if mirroring is enabled
if (SDL_Init(SDL_INIT_VIDEO)) {
if (options->video && SDL_Init(SDL_INIT_VIDEO)) {
LOGE("Could not initialize SDL video: %s", SDL_GetError());
goto end;
}
Expand Down Expand Up @@ -436,11 +437,13 @@ scrcpy(struct scrcpy_options *options) {
file_pusher_initialized = true;
}

static const struct sc_demuxer_callbacks video_demuxer_cbs = {
.on_ended = sc_video_demuxer_on_ended,
};
sc_demuxer_init(&s->video_demuxer, "video", s->server.video_socket,
&video_demuxer_cbs, NULL);
if (options->video) {
static const struct sc_demuxer_callbacks video_demuxer_cbs = {
.on_ended = sc_video_demuxer_on_ended,
};
sc_demuxer_init(&s->video_demuxer, "video", s->server.video_socket,
&video_demuxer_cbs, NULL);
}

if (options->audio) {
static const struct sc_demuxer_callbacks audio_demuxer_cbs = {
Expand All @@ -450,7 +453,7 @@ scrcpy(struct scrcpy_options *options) {
&audio_demuxer_cbs, options);
}

bool needs_video_decoder = options->mirror;
bool needs_video_decoder = options->mirror && options->video;
bool needs_audio_decoder = options->mirror && options->audio;
#ifdef HAVE_V4L2
needs_video_decoder |= !!options->v4l2_device;
Expand All @@ -471,8 +474,8 @@ scrcpy(struct scrcpy_options *options) {
.on_ended = sc_recorder_on_ended,
};
if (!sc_recorder_init(&s->recorder, options->record_filename,
options->record_format, options->audio,
&recorder_cbs, NULL)) {
options->record_format, options->video,
options->audio, &recorder_cbs, NULL)) {
goto end;
}
recorder_initialized = true;
Expand All @@ -482,8 +485,10 @@ scrcpy(struct scrcpy_options *options) {
}
recorder_started = true;

sc_packet_source_add_sink(&s->video_demuxer.packet_source,
&s->recorder.video_packet_sink);
if (options->video) {
sc_packet_source_add_sink(&s->video_demuxer.packet_source,
&s->recorder.video_packet_sink);
}
if (options->audio) {
sc_packet_source_add_sink(&s->audio_demuxer.packet_source,
&s->recorder.audio_packet_sink);
Expand Down Expand Up @@ -671,11 +676,6 @@ scrcpy(struct scrcpy_options *options) {
.start_fps_counter = options->start_fps_counter,
};

if (!sc_screen_init(&s->screen, &screen_params)) {
goto end;
}
screen_initialized = true;

struct sc_frame_source *src = &s->video_decoder.frame_source;
if (options->display_buffer) {
sc_delay_buffer_init(&s->display_buffer, options->display_buffer,
Expand All @@ -684,7 +684,14 @@ scrcpy(struct scrcpy_options *options) {
src = &s->display_buffer.frame_source;
}

sc_frame_source_add_sink(src, &s->screen.frame_sink);
if (options->video) {
if (!sc_screen_init(&s->screen, &screen_params)) {
goto end;
}
screen_initialized = true;

sc_frame_source_add_sink(src, &s->screen.frame_sink);
}

if (options->audio) {
sc_audio_player_init(&s->audio_player, options->audio_buffer,
Expand Down Expand Up @@ -713,12 +720,15 @@ scrcpy(struct scrcpy_options *options) {
}
#endif

// now we consumed the header values, the socket receives the video stream
// start the video demuxer
if (!sc_demuxer_start(&s->video_demuxer)) {
goto end;
// Now that the header values have been consumed, the socket(s) will
// receive the stream(s). Start the demuxer(s).

if (options->video) {
if (!sc_demuxer_start(&s->video_demuxer)) {
goto end;
}
video_demuxer_started = true;
}
video_demuxer_started = true;

if (options->audio) {
if (!sc_demuxer_start(&s->audio_demuxer)) {
Expand Down
Loading

0 comments on commit 8c650e5

Please sign in to comment.