diff --git a/app/meson.build b/app/meson.build index 99581c4a..a3c453da 100644 --- a/app/meson.build +++ b/app/meson.build @@ -47,6 +47,7 @@ if not get_option('crossbuild_windows') dependency('libavformat'), dependency('libavcodec'), dependency('libavutil'), + dependency('libswscale'), dependency('sdl2'), ] diff --git a/app/src/resizer.c b/app/src/resizer.c index 782a847a..977878d8 100644 --- a/app/src/resizer.c +++ b/app/src/resizer.c @@ -1,12 +1,14 @@ #include "resizer.h" #include +#include #include "util/log.h" bool sc_resizer_init(struct sc_resizer *resizer, struct video_buffer *vb_in, - struct video_buffer *vb_out, struct size size) { + struct video_buffer *vb_out, enum sc_scale_filter scale_filter, + struct size size) { bool ok = sc_mutex_init(&resizer->mutex); if (!ok) { return false; @@ -27,6 +29,7 @@ sc_resizer_init(struct sc_resizer *resizer, struct video_buffer *vb_in, resizer->vb_in = vb_in; resizer->vb_out = vb_out; + resizer->scale_filter = scale_filter; resizer->size = size; resizer->input_frame = NULL; @@ -44,11 +47,57 @@ sc_resizer_destroy(struct sc_resizer *resizer) { sc_mutex_destroy(&resizer->mutex); } +static int +to_sws_filter(enum sc_scale_filter scale_filter) { + switch (scale_filter) { + case SC_SCALE_FILTER_BILINEAR: return SWS_BILINEAR; + case SC_SCALE_FILTER_BICUBIC: return SWS_BICUBIC; + case SC_SCALE_FILTER_X: return SWS_X; + case SC_SCALE_FILTER_POINT: return SWS_POINT; + case SC_SCALE_FILTER_AREA: return SWS_AREA; + case SC_SCALE_FILTER_BICUBLIN: return SWS_BICUBLIN; + case SC_SCALE_FILTER_GAUSS: return SWS_GAUSS; + case SC_SCALE_FILTER_SINC: return SWS_SINC; + case SC_SCALE_FILTER_LANCZOS: return SWS_LANCZOS; + case SC_SCALE_FILTER_SPLINE: return SWS_SPLINE; + default: assert(!"unsupported filter"); + } +} + static bool sc_resizer_swscale(struct sc_resizer *resizer) { assert(!resizer->resized_frame->buf[0]); // The frame must be "empty" + assert(resizer->size.width); + assert(resizer->size.height); - return false; + const AVFrame *in = resizer->input_frame; + struct size size = resizer->size; + + AVFrame *out = resizer->resized_frame; + out->format = AV_PIX_FMT_RGB24; + out->width = size.width; + out->height = size.height; + + int ret = av_frame_get_buffer(out, 32); + if (ret < 0) { + return false; + } + + int flags = to_sws_filter(resizer->scale_filter); + struct SwsContext *ctx = + sws_getContext(in->width, in->height, AV_PIX_FMT_YUV420P, + size.width, size.height, AV_PIX_FMT_RGB24, flags, NULL, + NULL, NULL); + if (!ctx) { + av_frame_unref(out); + return false; + } + + sws_scale(ctx, (const uint8_t *const *) in->data, in->linesize, 0, + in->height, out->data, out->linesize); + sws_freeContext(ctx); + + return true; } static int diff --git a/app/src/resizer.h b/app/src/resizer.h index eb1d929c..5bd53de7 100644 --- a/app/src/resizer.h +++ b/app/src/resizer.h @@ -7,12 +7,14 @@ #include #include "coords.h" +#include "scrcpy.h" #include "util/thread.h" #include "video_buffer.h" struct sc_resizer { struct video_buffer *vb_in; struct video_buffer *vb_out; + enum sc_scale_filter scale_filter; struct size size; // valid until the next call to video_buffer_consumer_take_frame(vb_in) @@ -30,7 +32,8 @@ struct sc_resizer { bool sc_resizer_init(struct sc_resizer *resizer, struct video_buffer *vb_in, - struct video_buffer *vb_out, struct size initial_size); + struct video_buffer *vb_out, enum sc_scale_filter scale_filter, + struct size size); void sc_resizer_destroy(struct sc_resizer *resizer); diff --git a/app/src/scrcpy.h b/app/src/scrcpy.h index a89fa59c..1df6b2f9 100644 --- a/app/src/scrcpy.h +++ b/app/src/scrcpy.h @@ -44,6 +44,17 @@ struct sc_port_range { enum sc_scale_filter { SC_SCALE_FILTER_NONE, SC_SCALE_FILTER_TRILINEAR, // mipmaps + SC_SCALE_FILTER_BILINEAR, + SC_SCALE_FILTER_BICUBIC, + SC_SCALE_FILTER_X, + SC_SCALE_FILTER_POINT, + SC_SCALE_FILTER_AREA, + SC_SCALE_FILTER_BICUBLIN, + SC_SCALE_FILTER_GAUSS, + SC_SCALE_FILTER_SINC, + SC_SCALE_FILTER_LANCZOS, + SC_SCALE_FILTER_SPLINE, + SC_SCALE_FILTER__COUNT, }; #define SC_WINDOW_POSITION_UNDEFINED (-0x8000)