mirror of
https://github.com/Genymobile/scrcpy.git
synced 2025-04-21 03:55:05 +00:00
swscale-wip
This commit is contained in:
parent
a2d1709bfc
commit
c6ccb6a9a9
7 changed files with 156 additions and 7 deletions
|
@ -47,6 +47,7 @@ if not get_option('crossbuild_windows')
|
|||
dependency('libavformat'),
|
||||
dependency('libavcodec'),
|
||||
dependency('libavutil'),
|
||||
dependency('libswscale'),
|
||||
dependency('sdl2'),
|
||||
]
|
||||
|
||||
|
|
|
@ -642,6 +642,7 @@ guess_record_format(const char *filename) {
|
|||
|
||||
static bool
|
||||
parse_scale_filter(const char *optarg, enum sc_scale_filter *filter) {
|
||||
// TODO store in a map and loop over the entries instead
|
||||
if (!strcmp(optarg, "none")) {
|
||||
*filter = SC_SCALE_FILTER_NONE;
|
||||
return true;
|
||||
|
@ -650,8 +651,49 @@ parse_scale_filter(const char *optarg, enum sc_scale_filter *filter) {
|
|||
*filter = SC_SCALE_FILTER_TRILINEAR;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "bilinear")) {
|
||||
*filter = SC_SCALE_FILTER_BILINEAR;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "bicubic")) {
|
||||
*filter = SC_SCALE_FILTER_BICUBIC;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "x")) {
|
||||
*filter = SC_SCALE_FILTER_X;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "point")) {
|
||||
*filter = SC_SCALE_FILTER_POINT;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "area")) {
|
||||
*filter = SC_SCALE_FILTER_AREA;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "bicublin")) {
|
||||
*filter = SC_SCALE_FILTER_BICUBLIN;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "gauss")) {
|
||||
*filter = SC_SCALE_FILTER_GAUSS;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "sinc")) {
|
||||
*filter = SC_SCALE_FILTER_SINC;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "lanczos")) {
|
||||
*filter = SC_SCALE_FILTER_LANCZOS;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "spline")) {
|
||||
*filter = SC_SCALE_FILTER_SPLINE;
|
||||
return true;
|
||||
}
|
||||
|
||||
LOGE("Unsupported scale filter: %s "
|
||||
"(expected \"none\" or \"trilinear\")", optarg);
|
||||
"(expected one of [TODO])", optarg);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
#include "resizer.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <libswscale/swscale.h>
|
||||
|
||||
#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
|
||||
|
|
|
@ -7,12 +7,14 @@
|
|||
#include <libavformat/avformat.h>
|
||||
|
||||
#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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -241,7 +241,7 @@ create_texture(struct screen *screen) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (screen->mipmaps) {
|
||||
if (screen->scale_filter == SC_SCALE_FILTER_TRILINEAR) {
|
||||
struct sc_opengl *gl = &screen->gl;
|
||||
|
||||
SDL_GL_BindTexture(texture, NULL, NULL);
|
||||
|
@ -257,6 +257,12 @@ create_texture(struct screen *screen) {
|
|||
return texture;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
is_swscale(enum sc_scale_filter scale_filter) {
|
||||
return scale_filter != SC_SCALE_FILTER_NONE
|
||||
&& scale_filter != SC_SCALE_FILTER_TRILINEAR;
|
||||
}
|
||||
|
||||
bool
|
||||
screen_init_rendering(struct screen *screen, const char *window_title,
|
||||
struct size frame_size, bool always_on_top,
|
||||
|
@ -329,10 +335,10 @@ screen_init_rendering(struct screen *screen, const char *window_title,
|
|||
2, 0 /* OpenGL ES 2.0+ */);
|
||||
if (supports_mipmaps) {
|
||||
LOGI("Trilinear filtering enabled");
|
||||
screen->mipmaps = true;
|
||||
} else {
|
||||
LOGW("Trilinear filtering disabled "
|
||||
"(OpenGL 3.0+ or ES 2.0+ required)");
|
||||
scale_filter = SC_SCALE_FILTER_NONE;
|
||||
}
|
||||
} else {
|
||||
LOGI("Trilinear filtering disabled");
|
||||
|
@ -341,6 +347,29 @@ screen_init_rendering(struct screen *screen, const char *window_title,
|
|||
LOGD("Trilinear filtering disabled (not an OpenGL renderer)");
|
||||
}
|
||||
|
||||
screen->use_swscale = is_swscale(scale_filter);
|
||||
if (screen->use_swscale) {
|
||||
bool ok = sc_resizer_init(&screen->resizer, screen->vb,
|
||||
&screen->resizer_vb, scale_filter,
|
||||
window_size);
|
||||
if (!ok) {
|
||||
LOGE("Could not create resizer");
|
||||
SDL_DestroyRenderer(screen->renderer);
|
||||
SDL_DestroyWindow(screen->window);
|
||||
return false;
|
||||
}
|
||||
|
||||
ok = sc_resizer_start(&screen->resizer);
|
||||
if (!ok) {
|
||||
LOGE("Could not start resizer");
|
||||
sc_resizer_destroy(&screen->resizer);
|
||||
SDL_DestroyRenderer(screen->renderer);
|
||||
SDL_DestroyWindow(screen->window);
|
||||
}
|
||||
}
|
||||
|
||||
screen->scale_filter = scale_filter;
|
||||
|
||||
SDL_Surface *icon = read_xpm(icon_xpm);
|
||||
if (icon) {
|
||||
SDL_SetWindowIcon(screen->window, icon);
|
||||
|
@ -376,6 +405,11 @@ screen_show_window(struct screen *screen) {
|
|||
|
||||
void
|
||||
screen_destroy(struct screen *screen) {
|
||||
if (screen->use_swscale) {
|
||||
sc_resizer_stop(&screen->resizer);
|
||||
sc_resizer_join(&screen->resizer);
|
||||
sc_resizer_destroy(&screen->resizer);
|
||||
}
|
||||
if (screen->texture) {
|
||||
SDL_DestroyTexture(screen->texture);
|
||||
}
|
||||
|
@ -476,7 +510,7 @@ update_texture(struct screen *screen, const AVFrame *frame) {
|
|||
frame->data[1], frame->linesize[1],
|
||||
frame->data[2], frame->linesize[2]);
|
||||
|
||||
if (screen->mipmaps) {
|
||||
if (screen->scale_filter == SC_SCALE_FILTER_TRILINEAR) {
|
||||
SDL_GL_BindTexture(screen->texture, NULL, NULL);
|
||||
screen->gl.GenerateMipmap(GL_TEXTURE_2D);
|
||||
SDL_GL_UnbindTexture(screen->texture);
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
|
||||
#include "coords.h"
|
||||
#include "opengl.h"
|
||||
#include "resizer.h"
|
||||
#include "scrcpy.h"
|
||||
#include "video_buffer.h"
|
||||
|
||||
struct video_buffer;
|
||||
|
||||
|
@ -37,6 +39,13 @@ struct screen {
|
|||
bool fullscreen;
|
||||
bool maximized;
|
||||
bool mipmaps;
|
||||
|
||||
enum sc_scale_filter scale_filter;
|
||||
bool use_swscale;
|
||||
|
||||
// For swscale resizing
|
||||
struct video_buffer resizer_vb;
|
||||
struct sc_resizer resizer;
|
||||
};
|
||||
|
||||
// initialize default values
|
||||
|
|
Loading…
Add table
Reference in a new issue