Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions app/deps/ffmpeg.sh
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,14 @@ else
--extra-cflags="-O2 -fPIC"
--disable-programs
--disable-doc
--disable-swscale
--disable-postproc
--disable-avfilter
--disable-network
--disable-everything
--disable-vulkan
--disable-vaapi
--disable-vdpau
--enable-swresample
--enable-swscale
--enable-libdav1d
--enable-decoder=h264
--enable-decoder=hevc
Expand All @@ -79,6 +78,12 @@ else
--enable-muxer=opus
--enable-muxer=flac
--enable-muxer=wav
--enable-filter=buffer
--enable-filter=buffersink
--enable-filter=format
--enable-filter=scale
--enable-filter=lenscorrection
--enable-filter=v360
)

if [[ "$HOST" == linux ]]
Expand Down
3 changes: 3 additions & 0 deletions app/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ src = [
'src/recorder.c',
'src/scrcpy.c',
'src/screen.c',
'src/video_filter.c',
'src/server.c',
'src/version.c',
'src/hid/hid_gamepad.c',
Expand Down Expand Up @@ -116,6 +117,8 @@ dependencies = [
dependency('libavformat', version: '>= 57.33', static: static),
dependency('libavcodec', version: '>= 57.37', static: static),
dependency('libavutil', static: static),
dependency('libavfilter', static: static),
dependency('libswscale', static: static),
dependency('libswresample', static: static),
dependency('sdl2', version: '>= 2.0.5', static: static),
]
Expand Down
6 changes: 6 additions & 0 deletions app/scrcpy.1
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,12 @@ The list of possible codec options is available in the Android documentation:

<https://d.android.com/reference/android/media/MediaFormat>

.TP
.BI "\-\-video\-filter " filter
Apply an FFmpeg filter graph to the decoded video before it is displayed or forwarded to V4L2.

Example: --video-filter="lenscorrection=cx=0.5:cy=0.5:k1=-0.2:k2=0"

.TP
.BI "\-\-video\-encoder " name
Use a specific MediaCodec video encoder (depending on the codec provided by \fB\-\-video\-codec\fR).
Expand Down
13 changes: 13 additions & 0 deletions app/src/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ enum {
OPT_NO_MIPMAPS,
OPT_CODEC_OPTIONS,
OPT_VIDEO_CODEC_OPTIONS,
OPT_VIDEO_FILTER,
OPT_FORCE_ADB_FORWARD,
OPT_DISABLE_SCREENSAVER,
OPT_SHORTCUT_MOD,
Expand Down Expand Up @@ -1006,6 +1007,15 @@ static const struct sc_option options[] = {
"Android documentation: "
"<https://d.android.com/reference/android/media/MediaFormat>",
},
{
.longopt_id = OPT_VIDEO_FILTER,
.longopt = "video-filter",
.argdesc = "filter",
.text = "Apply an FFmpeg filter graph on the decoded video before it "
"is rendered or forwarded to V4L2.\n"
"Example: --video-filter=\"lenscorrection=cx=0.5:cy=0.5:"
"k1=-0.2:k2=0\"",
},
{
.longopt_id = OPT_VIDEO_ENCODER,
.longopt = "video-encoder",
Expand Down Expand Up @@ -2656,6 +2666,9 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
case OPT_VIDEO_CODEC_OPTIONS:
opts->video_codec_options = optarg;
break;
case OPT_VIDEO_FILTER:
opts->video_filter = optarg;
break;
case OPT_AUDIO_CODEC_OPTIONS:
opts->audio_codec_options = optarg;
break;
Expand Down
1 change: 1 addition & 0 deletions app/src/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const struct scrcpy_options scrcpy_options_default = {
.push_target = NULL,
.render_driver = NULL,
.video_codec_options = NULL,
.video_filter = NULL,
.audio_codec_options = NULL,
.video_encoder = NULL,
.audio_encoder = NULL,
Expand Down
1 change: 1 addition & 0 deletions app/src/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ struct scrcpy_options {
const char *push_target;
const char *render_driver;
const char *video_codec_options;
const char *video_filter;
const char *audio_codec_options;
const char *video_encoder;
const char *audio_encoder;
Expand Down
28 changes: 26 additions & 2 deletions app/src/scrcpy.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "recorder.h"
#include "screen.h"
#include "server.h"
#include "video_filter.h"
#include "uhid/gamepad_uhid.h"
#include "uhid/keyboard_uhid.h"
#include "uhid/mouse_uhid.h"
Expand Down Expand Up @@ -55,6 +56,7 @@ struct scrcpy {
struct sc_decoder audio_decoder;
struct sc_recorder recorder;
struct sc_delay_buffer video_buffer;
struct sc_video_filter video_filter;
#ifdef HAVE_V4L2
struct sc_v4l2_sink v4l2_sink;
struct sc_delay_buffer v4l2_buffer;
Expand Down Expand Up @@ -392,6 +394,7 @@ scrcpy(struct scrcpy_options *options) {
#ifdef HAVE_V4L2
bool v4l2_sink_initialized = false;
#endif
bool video_filter_initialized = false;
bool video_demuxer_started = false;
bool audio_demuxer_started = false;
#ifdef HAVE_USB
Expand Down Expand Up @@ -582,10 +585,12 @@ scrcpy(struct scrcpy_options *options) {
#ifdef HAVE_V4L2
needs_video_decoder |= !!options->v4l2_device;
#endif
bool video_decoder_initialized = false;
if (needs_video_decoder) {
sc_decoder_init(&s->video_decoder, "video");
sc_packet_source_add_sink(&s->video_demuxer.packet_source,
&s->video_decoder.packet_sink);
video_decoder_initialized = true;
}
if (needs_audio_decoder) {
sc_decoder_init(&s->audio_decoder, "audio");
Expand Down Expand Up @@ -786,6 +791,21 @@ scrcpy(struct scrcpy_options *options) {
// There is a controller if and only if control is enabled
assert(options->control == !!controller);

if (options->video_filter && !video_decoder_initialized) {
LOGW("Ignoring --video-filter: video playback is disabled");
}

struct sc_frame_source *video_source = &s->video_decoder.frame_source;
if (video_decoder_initialized && options->video_filter) {
if (!sc_video_filter_init(&s->video_filter, options->video_filter)) {
goto end;
}

video_filter_initialized = true;
sc_frame_source_add_sink(video_source, &s->video_filter.frame_sink);
video_source = &s->video_filter.frame_source;
}

if (options->window) {
const char *window_title =
options->window_title ? options->window_title : info->device_name;
Expand Down Expand Up @@ -825,7 +845,7 @@ scrcpy(struct scrcpy_options *options) {
screen_initialized = true;

if (options->video_playback) {
struct sc_frame_source *src = &s->video_decoder.frame_source;
struct sc_frame_source *src = video_source;
if (options->video_buffer) {
sc_delay_buffer_init(&s->video_buffer,
options->video_buffer, true);
Expand All @@ -850,7 +870,7 @@ scrcpy(struct scrcpy_options *options) {
goto end;
}

struct sc_frame_source *src = &s->video_decoder.frame_source;
struct sc_frame_source *src = video_source;
if (options->v4l2_buffer) {
sc_delay_buffer_init(&s->v4l2_buffer, options->v4l2_buffer, true);
sc_frame_source_add_sink(src, &s->v4l2_buffer.frame_sink);
Expand Down Expand Up @@ -1051,6 +1071,10 @@ scrcpy(struct scrcpy_options *options) {
sc_file_pusher_destroy(&s->file_pusher);
}

if (video_filter_initialized) {
sc_video_filter_destroy(&s->video_filter);
}

if (server_started) {
sc_server_join(&s->server);
}
Expand Down
Loading
Loading