mirror of
https://github.com/Genymobile/scrcpy.git
synced 2026-03-22 03:54:43 +01:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0308ef43f2 | ||
|
|
40febf4a91 | ||
|
|
429fdef04f | ||
|
|
d1789f082a | ||
|
|
eb7e1070cf | ||
|
|
386f017ba9 | ||
|
|
cc48b24324 | ||
|
|
597c54f049 | ||
|
|
955da3b578 | ||
|
|
cb9c42bdcb | ||
|
|
fb9f9848bd | ||
|
|
c50b958ee4 | ||
|
|
441d3fb119 | ||
|
|
cb197ee3a2 | ||
|
|
218636dc10 |
@@ -15,7 +15,6 @@ src = [
|
||||
'src/opengl.c',
|
||||
'src/receiver.c',
|
||||
'src/recorder.c',
|
||||
'src/resizer.c',
|
||||
'src/scrcpy.c',
|
||||
'src/screen.c',
|
||||
'src/server.c',
|
||||
|
||||
@@ -167,13 +167,6 @@ Set the initial display rotation. Possibles values are 0, 1, 2 and 3. Each incre
|
||||
.BI "\-s, \-\-serial " number
|
||||
The device serial number. Mandatory only if several devices are connected to adb.
|
||||
|
||||
.TP
|
||||
.BI "\-\-scale\-filter filter
|
||||
Supported filters are "none" and "trilinear".
|
||||
|
||||
Trilinear filtering is only available if the renderer is OpenGL 3.0+ or OpenGL
|
||||
ES 2.0+.
|
||||
|
||||
.TP
|
||||
.BI "\-\-shortcut\-mod " key[+...]][,...]
|
||||
Specify the modifiers to use for scrcpy shortcuts. Possible keys are "lctrl", "rctrl", "lalt", "ralt", "lsuper" and "rsuper".
|
||||
|
||||
@@ -106,6 +106,11 @@ scrcpy_print_usage(const char *arg0) {
|
||||
" --no-key-repeat\n"
|
||||
" Do not forward repeated key events when a key is held down.\n"
|
||||
"\n"
|
||||
" --no-mipmaps\n"
|
||||
" If the renderer is OpenGL 3.0+ or OpenGL ES 2.0+, then\n"
|
||||
" mipmaps are automatically generated to improve downscaling\n"
|
||||
" quality. This option disables the generation of mipmaps.\n"
|
||||
"\n"
|
||||
" -p, --port port[:port]\n"
|
||||
" Set the TCP port (range) used by the client to listen.\n"
|
||||
" Default is " STR(DEFAULT_LOCAL_PORT_RANGE_FIRST) ":"
|
||||
@@ -153,11 +158,6 @@ scrcpy_print_usage(const char *arg0) {
|
||||
" The device serial number. Mandatory only if several devices\n"
|
||||
" are connected to adb.\n"
|
||||
"\n"
|
||||
" --scale-filter filter\n"
|
||||
" Supported filters are \"none\" and \"trilinear\".\n"
|
||||
" Trilinear filtering is only available if the renderer is\n"
|
||||
" OpenGL 3.0+ or OpenGL ES 2.0+.\n"
|
||||
"\n"
|
||||
" --shortcut-mod key[+...]][,...]\n"
|
||||
" Specify the modifiers to use for scrcpy shortcuts.\n"
|
||||
" Possible keys are \"lctrl\", \"rctrl\", \"lalt\", \"ralt\",\n"
|
||||
@@ -640,21 +640,6 @@ guess_record_format(const char *filename) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_scale_filter(const char *optarg, enum sc_scale_filter *filter) {
|
||||
if (!strcmp(optarg, "none")) {
|
||||
*filter = SC_SCALE_FILTER_NONE;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "trilinear")) {
|
||||
*filter = SC_SCALE_FILTER_TRILINEAR;
|
||||
return true;
|
||||
}
|
||||
LOGE("Unsupported scale filter: %s "
|
||||
"(expected \"none\" or \"trilinear\")", optarg);
|
||||
return false;
|
||||
}
|
||||
|
||||
#define OPT_RENDER_EXPIRED_FRAMES 1000
|
||||
#define OPT_WINDOW_TITLE 1001
|
||||
#define OPT_PUSH_TARGET 1002
|
||||
@@ -681,7 +666,6 @@ parse_scale_filter(const char *optarg, enum sc_scale_filter *filter) {
|
||||
#define OPT_FORWARD_ALL_CLICKS 1023
|
||||
#define OPT_LEGACY_PASTE 1024
|
||||
#define OPT_ENCODER_NAME 1025
|
||||
#define OPT_SCALE_FILTER 1026
|
||||
|
||||
bool
|
||||
scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
||||
@@ -718,7 +702,6 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
||||
{"render-expired-frames", no_argument, NULL,
|
||||
OPT_RENDER_EXPIRED_FRAMES},
|
||||
{"rotation", required_argument, NULL, OPT_ROTATION},
|
||||
{"scale-filter", required_argument, NULL, OPT_SCALE_FILTER},
|
||||
{"serial", required_argument, NULL, 's'},
|
||||
{"shortcut-mod", required_argument, NULL, OPT_SHORTCUT_MOD},
|
||||
{"show-touches", no_argument, NULL, 't'},
|
||||
@@ -873,9 +856,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
||||
opts->render_driver = optarg;
|
||||
break;
|
||||
case OPT_NO_MIPMAPS:
|
||||
LOGW("Deprecated option --no-mipmaps. "
|
||||
"Use --scale-filter=none instead.");
|
||||
opts->scale_filter = SC_SCALE_FILTER_NONE;
|
||||
opts->mipmaps = false;
|
||||
break;
|
||||
case OPT_NO_KEY_REPEAT:
|
||||
opts->forward_key_repeat = false;
|
||||
@@ -903,11 +884,6 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
||||
case OPT_LEGACY_PASTE:
|
||||
opts->legacy_paste = true;
|
||||
break;
|
||||
case OPT_SCALE_FILTER:
|
||||
if (!parse_scale_filter(optarg, &opts->scale_filter)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// getopt prints the error message on stderr
|
||||
return false;
|
||||
|
||||
@@ -30,20 +30,11 @@ decoder_open(struct decoder *decoder, const AVCodec *codec) {
|
||||
return false;
|
||||
}
|
||||
|
||||
decoder->frame = av_frame_alloc();
|
||||
if (!decoder->frame) {
|
||||
LOGE("Could not create decoder frame");
|
||||
avcodec_close(decoder->codec_ctx);
|
||||
avcodec_free_context(&decoder->codec_ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
decoder_close(struct decoder *decoder) {
|
||||
av_frame_free(&decoder->frame);
|
||||
avcodec_close(decoder->codec_ctx);
|
||||
avcodec_free_context(&decoder->codec_ctx);
|
||||
}
|
||||
@@ -58,11 +49,11 @@ decoder_push(struct decoder *decoder, const AVPacket *packet) {
|
||||
LOGE("Could not send video packet: %d", ret);
|
||||
return false;
|
||||
}
|
||||
ret = avcodec_receive_frame(decoder->codec_ctx, decoder->frame);
|
||||
ret = avcodec_receive_frame(decoder->codec_ctx,
|
||||
decoder->video_buffer->producer_frame);
|
||||
if (!ret) {
|
||||
// a frame was received
|
||||
video_buffer_producer_offer_frame(decoder->video_buffer,
|
||||
&decoder->frame);
|
||||
video_buffer_producer_offer_frame(decoder->video_buffer);
|
||||
} else if (ret != AVERROR(EAGAIN)) {
|
||||
LOGE("Could not receive video frame: %d", ret);
|
||||
return false;
|
||||
@@ -70,7 +61,7 @@ decoder_push(struct decoder *decoder, const AVPacket *packet) {
|
||||
#else
|
||||
int got_picture;
|
||||
int len = avcodec_decode_video2(decoder->codec_ctx,
|
||||
decoder->frame,
|
||||
decoder->video_buffer->decoding_frame,
|
||||
&got_picture,
|
||||
packet);
|
||||
if (len < 0) {
|
||||
|
||||
@@ -12,7 +12,6 @@ struct decoder {
|
||||
struct video_buffer *video_buffer;
|
||||
|
||||
AVCodecContext *codec_ctx;
|
||||
AVFrame *frame;
|
||||
};
|
||||
|
||||
void
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
#include "resizer.h"
|
||||
|
||||
#include <assert.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) {
|
||||
bool ok = sc_mutex_init(&resizer->mutex);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ok = sc_cond_init(&resizer->req_cond);
|
||||
if (!ok) {
|
||||
sc_mutex_destroy(&resizer->mutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
resizer->resized_frame = av_frame_alloc();
|
||||
if (!resizer->resized_frame) {
|
||||
sc_cond_destroy(&resizer->req_cond);
|
||||
sc_mutex_destroy(&resizer->mutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
resizer->vb_in = vb_in;
|
||||
resizer->vb_out = vb_out;
|
||||
resizer->size = size;
|
||||
|
||||
resizer->input_frame = NULL;
|
||||
resizer->has_request = false;
|
||||
resizer->has_new_frame = false;
|
||||
resizer->interrupted = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
sc_resizer_destroy(struct sc_resizer *resizer) {
|
||||
av_frame_free(&resizer->resized_frame);
|
||||
sc_cond_destroy(&resizer->req_cond);
|
||||
sc_mutex_destroy(&resizer->mutex);
|
||||
}
|
||||
|
||||
static bool
|
||||
sc_resizer_swscale(struct sc_resizer *resizer) {
|
||||
assert(!resizer->resized_frame->buf[0]); // The frame must be "empty"
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
run_resizer(void *data) {
|
||||
struct sc_resizer *resizer = data;
|
||||
|
||||
sc_mutex_lock(&resizer->mutex);
|
||||
while (!resizer->interrupted) {
|
||||
while (!resizer->interrupted && !resizer->has_request) {
|
||||
sc_cond_wait(&resizer->req_cond, &resizer->mutex);
|
||||
}
|
||||
|
||||
if (resizer->has_new_frame) {
|
||||
resizer->input_frame =
|
||||
video_buffer_consumer_take_frame(resizer->vb_in);
|
||||
|
||||
resizer->has_new_frame = false;
|
||||
}
|
||||
|
||||
resizer->has_request = false;
|
||||
sc_mutex_unlock(&resizer->mutex);
|
||||
|
||||
// Do the actual work without mutex
|
||||
sc_resizer_swscale(resizer);
|
||||
|
||||
video_buffer_producer_offer_frame(resizer->vb_out,
|
||||
&resizer->resized_frame);
|
||||
|
||||
sc_mutex_lock(&resizer->mutex);
|
||||
}
|
||||
sc_mutex_unlock(&resizer->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
sc_resizer_start(struct sc_resizer *resizer) {
|
||||
LOGD("Starting resizer thread");
|
||||
|
||||
bool ok = sc_thread_create(&resizer->thread, run_resizer, "resizer",
|
||||
resizer);
|
||||
if (!ok) {
|
||||
LOGE("Could not start resizer thread");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
sc_resizer_stop(struct sc_resizer *resizer) {
|
||||
sc_mutex_lock(&resizer->mutex);
|
||||
resizer->interrupted = true;
|
||||
sc_cond_signal(&resizer->req_cond);
|
||||
sc_mutex_unlock(&resizer->mutex);
|
||||
|
||||
video_buffer_interrupt(resizer->vb_out);
|
||||
}
|
||||
|
||||
void
|
||||
sc_resizer_join(struct sc_resizer *resizer) {
|
||||
sc_thread_join(&resizer->thread, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
sc_resizer_process_new_frame(struct sc_resizer *resizer) {
|
||||
sc_mutex_lock(&resizer->mutex);
|
||||
resizer->has_request = true;
|
||||
resizer->has_new_frame = true;
|
||||
sc_cond_signal(&resizer->req_cond);
|
||||
sc_mutex_unlock(&resizer->mutex);
|
||||
}
|
||||
|
||||
void
|
||||
sc_resizer_process_new_size(struct sc_resizer *resizer, struct size size) {
|
||||
sc_mutex_lock(&resizer->mutex);
|
||||
resizer->size = size;
|
||||
resizer->has_request = true;
|
||||
sc_cond_signal(&resizer->req_cond);
|
||||
sc_mutex_unlock(&resizer->mutex);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
#ifndef SC_RESIZER
|
||||
#define SC_RESIZER
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
#include "coords.h"
|
||||
#include "util/thread.h"
|
||||
#include "video_buffer.h"
|
||||
|
||||
struct sc_resizer {
|
||||
struct video_buffer *vb_in;
|
||||
struct video_buffer *vb_out;
|
||||
struct size size;
|
||||
|
||||
// valid until the next call to video_buffer_consumer_take_frame(vb_in)
|
||||
const AVFrame *input_frame;
|
||||
AVFrame *resized_frame;
|
||||
|
||||
sc_thread thread;
|
||||
sc_mutex mutex;
|
||||
sc_cond req_cond;
|
||||
|
||||
bool has_request;
|
||||
bool has_new_frame;
|
||||
bool interrupted;
|
||||
};
|
||||
|
||||
bool
|
||||
sc_resizer_init(struct sc_resizer *resizer, struct video_buffer *vb_in,
|
||||
struct video_buffer *vb_out, struct size initial_size);
|
||||
|
||||
void
|
||||
sc_resizer_destroy(struct sc_resizer *resizer);
|
||||
|
||||
bool
|
||||
sc_resizer_start(struct sc_resizer *resizer);
|
||||
|
||||
void
|
||||
sc_resizer_stop(struct sc_resizer *resizer);
|
||||
|
||||
void
|
||||
sc_resizer_join(struct sc_resizer *resizer);
|
||||
|
||||
void
|
||||
sc_resizer_process_new_frame(struct sc_resizer *resizer);
|
||||
|
||||
void
|
||||
sc_resizer_process_new_size(struct sc_resizer *resizer, struct size size);
|
||||
|
||||
#endif
|
||||
@@ -392,7 +392,7 @@ scrcpy(const struct scrcpy_options *options) {
|
||||
.window_height = options->window_height,
|
||||
.window_borderless = options->window_borderless,
|
||||
.rotation = options->rotation,
|
||||
.scale_filter = options->scale_filter,
|
||||
.mipmaps = options->mipmaps,
|
||||
};
|
||||
|
||||
if (!screen_init(&screen, &video_buffer, &fps_counter,
|
||||
|
||||
@@ -41,11 +41,6 @@ struct sc_port_range {
|
||||
uint16_t last;
|
||||
};
|
||||
|
||||
enum sc_scale_filter {
|
||||
SC_SCALE_FILTER_NONE,
|
||||
SC_SCALE_FILTER_TRILINEAR, // mipmaps
|
||||
};
|
||||
|
||||
#define SC_WINDOW_POSITION_UNDEFINED (-0x8000)
|
||||
|
||||
struct scrcpy_options {
|
||||
@@ -61,7 +56,6 @@ struct scrcpy_options {
|
||||
enum sc_record_format record_format;
|
||||
struct sc_port_range port_range;
|
||||
struct sc_shortcut_mods shortcut_mods;
|
||||
enum sc_scale_filter scale_filter;
|
||||
uint16_t max_size;
|
||||
uint32_t bit_rate;
|
||||
uint16_t max_fps;
|
||||
@@ -81,6 +75,7 @@ struct scrcpy_options {
|
||||
bool render_expired_frames;
|
||||
bool prefer_text;
|
||||
bool window_borderless;
|
||||
bool mipmaps;
|
||||
bool stay_awake;
|
||||
bool force_adb_forward;
|
||||
bool disable_screensaver;
|
||||
@@ -108,7 +103,6 @@ struct scrcpy_options {
|
||||
.data = {SC_MOD_LALT, SC_MOD_LSUPER}, \
|
||||
.count = 2, \
|
||||
}, \
|
||||
.scale_filter = SC_SCALE_FILTER_TRILINEAR, \
|
||||
.max_size = 0, \
|
||||
.bit_rate = DEFAULT_BIT_RATE, \
|
||||
.max_fps = 0, \
|
||||
@@ -128,6 +122,7 @@ struct scrcpy_options {
|
||||
.render_expired_frames = false, \
|
||||
.prefer_text = false, \
|
||||
.window_borderless = false, \
|
||||
.mipmaps = true, \
|
||||
.stay_awake = false, \
|
||||
.force_adb_forward = false, \
|
||||
.disable_screensaver = false, \
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "events.h"
|
||||
#include "icon.xpm"
|
||||
#include "scrcpy.h"
|
||||
#include "tiny_xpm.h"
|
||||
#include "video_buffer.h"
|
||||
#include "util/log.h"
|
||||
@@ -313,14 +314,13 @@ screen_init(struct screen *screen, struct video_buffer *vb,
|
||||
|
||||
// starts with "opengl"
|
||||
bool use_opengl = renderer_name && !strncmp(renderer_name, "opengl", 6);
|
||||
bool mipmaps = params->scale_filter == SC_SCALE_FILTER_TRILINEAR;
|
||||
if (use_opengl) {
|
||||
struct sc_opengl *gl = &screen->gl;
|
||||
sc_opengl_init(gl);
|
||||
|
||||
LOGI("OpenGL version: %s", gl->version);
|
||||
|
||||
if (mipmaps) {
|
||||
if (params->mipmaps) {
|
||||
bool supports_mipmaps =
|
||||
sc_opengl_version_at_least(gl, 3, 0, /* OpenGL 3.0+ */
|
||||
2, 0 /* OpenGL ES 2.0+ */);
|
||||
@@ -334,7 +334,7 @@ screen_init(struct screen *screen, struct video_buffer *vb,
|
||||
} else {
|
||||
LOGI("Trilinear filtering disabled");
|
||||
}
|
||||
} else if (mipmaps) {
|
||||
} else if (params->mipmaps) {
|
||||
LOGD("Trilinear filtering disabled (not an OpenGL renderer)");
|
||||
}
|
||||
|
||||
@@ -356,15 +356,6 @@ screen_init(struct screen *screen, struct video_buffer *vb,
|
||||
return false;
|
||||
}
|
||||
|
||||
screen->frame = av_frame_alloc();
|
||||
if (!screen->frame) {
|
||||
LOGC("Could not create screen frame");
|
||||
SDL_DestroyTexture(screen->texture);
|
||||
SDL_DestroyRenderer(screen->renderer);
|
||||
SDL_DestroyWindow(screen->window);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reset the window size to trigger a SIZE_CHANGED event, to workaround
|
||||
// HiDPI issues with some SDL renderers when several displays having
|
||||
// different HiDPI scaling are connected
|
||||
@@ -382,7 +373,6 @@ screen_show_window(struct screen *screen) {
|
||||
|
||||
void
|
||||
screen_destroy(struct screen *screen) {
|
||||
av_frame_free(&screen->frame);
|
||||
SDL_DestroyTexture(screen->texture);
|
||||
SDL_DestroyRenderer(screen->renderer);
|
||||
SDL_DestroyWindow(screen->window);
|
||||
@@ -490,8 +480,7 @@ update_texture(struct screen *screen, const AVFrame *frame) {
|
||||
|
||||
static bool
|
||||
screen_update_frame(struct screen *screen) {
|
||||
video_buffer_consumer_take_frame(screen->vb, &screen->frame);
|
||||
AVFrame *frame = screen->frame;
|
||||
const AVFrame *frame = video_buffer_consumer_take_frame(screen->vb);
|
||||
|
||||
fps_counter_add_rendered_frame(screen->fps_counter);
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include "coords.h"
|
||||
#include "opengl.h"
|
||||
#include "scrcpy.h"
|
||||
|
||||
struct video_buffer;
|
||||
|
||||
@@ -37,8 +36,6 @@ struct screen {
|
||||
bool fullscreen;
|
||||
bool maximized;
|
||||
bool mipmaps;
|
||||
|
||||
AVFrame *frame;
|
||||
};
|
||||
|
||||
struct screen_params {
|
||||
@@ -54,7 +51,7 @@ struct screen_params {
|
||||
bool window_borderless;
|
||||
|
||||
uint8_t rotation;
|
||||
enum sc_scale_filter scale_filter;
|
||||
bool mipmaps;
|
||||
};
|
||||
|
||||
// initialize screen, create window, renderer and texture (window is hidden)
|
||||
|
||||
@@ -8,14 +8,24 @@
|
||||
|
||||
bool
|
||||
video_buffer_init(struct video_buffer *vb, bool wait_consumer) {
|
||||
vb->producer_frame = av_frame_alloc();
|
||||
if (!vb->producer_frame) {
|
||||
goto error_0;
|
||||
}
|
||||
|
||||
vb->pending_frame = av_frame_alloc();
|
||||
if (!vb->pending_frame) {
|
||||
goto error_0;
|
||||
goto error_1;
|
||||
}
|
||||
|
||||
vb->consumer_frame = av_frame_alloc();
|
||||
if (!vb->consumer_frame) {
|
||||
goto error_2;
|
||||
}
|
||||
|
||||
bool ok = sc_mutex_init(&vb->mutex);
|
||||
if (!ok) {
|
||||
goto error_1;
|
||||
goto error_3;
|
||||
}
|
||||
|
||||
vb->wait_consumer = wait_consumer;
|
||||
@@ -23,7 +33,7 @@ video_buffer_init(struct video_buffer *vb, bool wait_consumer) {
|
||||
ok = sc_cond_init(&vb->pending_frame_consumed_cond);
|
||||
if (!ok) {
|
||||
sc_mutex_destroy(&vb->mutex);
|
||||
goto error_1;
|
||||
goto error_2;
|
||||
}
|
||||
// interrupted is not used if wait_consumer is disabled since offering
|
||||
// a frame will never block
|
||||
@@ -39,8 +49,12 @@ video_buffer_init(struct video_buffer *vb, bool wait_consumer) {
|
||||
|
||||
return true;
|
||||
|
||||
error_1:
|
||||
error_3:
|
||||
av_frame_free(&vb->consumer_frame);
|
||||
error_2:
|
||||
av_frame_free(&vb->pending_frame);
|
||||
error_1:
|
||||
av_frame_free(&vb->producer_frame);
|
||||
error_0:
|
||||
return false;
|
||||
}
|
||||
@@ -51,7 +65,9 @@ video_buffer_destroy(struct video_buffer *vb) {
|
||||
sc_cond_destroy(&vb->pending_frame_consumed_cond);
|
||||
}
|
||||
sc_mutex_destroy(&vb->mutex);
|
||||
av_frame_free(&vb->consumer_frame);
|
||||
av_frame_free(&vb->pending_frame);
|
||||
av_frame_free(&vb->producer_frame);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -73,7 +89,7 @@ video_buffer_set_consumer_callbacks(struct video_buffer *vb,
|
||||
}
|
||||
|
||||
void
|
||||
video_buffer_producer_offer_frame(struct video_buffer *vb, AVFrame **pframe) {
|
||||
video_buffer_producer_offer_frame(struct video_buffer *vb) {
|
||||
assert(vb->cbs);
|
||||
|
||||
sc_mutex_lock(&vb->mutex);
|
||||
@@ -85,7 +101,7 @@ video_buffer_producer_offer_frame(struct video_buffer *vb, AVFrame **pframe) {
|
||||
}
|
||||
|
||||
av_frame_unref(vb->pending_frame);
|
||||
swap_frames(pframe, &vb->pending_frame);
|
||||
swap_frames(&vb->producer_frame, &vb->pending_frame);
|
||||
|
||||
bool skipped = !vb->pending_frame_consumed;
|
||||
vb->pending_frame_consumed = false;
|
||||
@@ -100,13 +116,13 @@ video_buffer_producer_offer_frame(struct video_buffer *vb, AVFrame **pframe) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
video_buffer_consumer_take_frame(struct video_buffer *vb, AVFrame **pframe) {
|
||||
const AVFrame *
|
||||
video_buffer_consumer_take_frame(struct video_buffer *vb) {
|
||||
sc_mutex_lock(&vb->mutex);
|
||||
assert(!vb->pending_frame_consumed);
|
||||
vb->pending_frame_consumed = true;
|
||||
|
||||
swap_frames(pframe, &vb->pending_frame);
|
||||
swap_frames(&vb->consumer_frame, &vb->pending_frame);
|
||||
av_frame_unref(vb->pending_frame);
|
||||
|
||||
if (vb->wait_consumer) {
|
||||
@@ -114,6 +130,9 @@ video_buffer_consumer_take_frame(struct video_buffer *vb, AVFrame **pframe) {
|
||||
sc_cond_signal(&vb->pending_frame_consumed_cond);
|
||||
}
|
||||
sc_mutex_unlock(&vb->mutex);
|
||||
|
||||
// consumer_frame is only written from this thread, no need to lock
|
||||
return vb->consumer_frame;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -29,7 +29,9 @@ typedef struct AVFrame AVFrame;
|
||||
*/
|
||||
|
||||
struct video_buffer {
|
||||
AVFrame *producer_frame;
|
||||
AVFrame *pending_frame;
|
||||
AVFrame *consumer_frame;
|
||||
|
||||
sc_mutex mutex;
|
||||
bool wait_consumer; // never overwrite a pending frame if it is not consumed
|
||||
@@ -65,14 +67,13 @@ video_buffer_set_consumer_callbacks(struct video_buffer *vb,
|
||||
void *cbs_userdata);
|
||||
|
||||
// set the producer frame as ready for consuming
|
||||
// the produced frame is exchanged with an unused allocated frame
|
||||
void
|
||||
video_buffer_producer_offer_frame(struct video_buffer *vb, AVFrame **pframe);
|
||||
video_buffer_producer_offer_frame(struct video_buffer *vb);
|
||||
|
||||
// mark the consumer frame as consumed and exchange it with an unused allocated
|
||||
// frame
|
||||
void
|
||||
video_buffer_consumer_take_frame(struct video_buffer *vb, AVFrame **pframe);
|
||||
// mark the consumer frame as consumed and return it
|
||||
// the frame is valid until the next call to this function
|
||||
const AVFrame *
|
||||
video_buffer_consumer_take_frame(struct video_buffer *vb);
|
||||
|
||||
// wake up and avoid any blocking call
|
||||
void
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
[binaries]
|
||||
name = 'mingw'
|
||||
c = '/usr/bin/i686-w64-mingw32-gcc'
|
||||
cpp = '/usr/bin/i686-w64-mingw32-g++'
|
||||
ar = '/usr/bin/i686-w64-mingw32-ar'
|
||||
strip = '/usr/bin/i686-w64-mingw32-strip'
|
||||
pkgconfig = '/usr/bin/i686-w64-mingw32-pkg-config'
|
||||
c = 'i686-w64-mingw32-gcc'
|
||||
cpp = 'i686-w64-mingw32-g++'
|
||||
ar = 'i686-w64-mingw32-ar'
|
||||
strip = 'i686-w64-mingw32-strip'
|
||||
pkgconfig = 'i686-w64-mingw32-pkg-config'
|
||||
|
||||
[host_machine]
|
||||
system = 'windows'
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
[binaries]
|
||||
name = 'mingw'
|
||||
c = '/usr/bin/x86_64-w64-mingw32-gcc'
|
||||
cpp = '/usr/bin/x86_64-w64-mingw32-g++'
|
||||
ar = '/usr/bin/x86_64-w64-mingw32-ar'
|
||||
strip = '/usr/bin/x86_64-w64-mingw32-strip'
|
||||
pkgconfig = '/usr/bin/x86_64-w64-mingw32-pkg-config'
|
||||
c = 'x86_64-w64-mingw32-gcc'
|
||||
cpp = 'x86_64-w64-mingw32-g++'
|
||||
ar = 'x86_64-w64-mingw32-ar'
|
||||
strip = 'x86_64-w64-mingw32-strip'
|
||||
pkgconfig = 'x86_64-w64-mingw32-pkg-config'
|
||||
|
||||
[host_machine]
|
||||
system = 'windows'
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class Controller {
|
||||
|
||||
private static final int DEVICE_ID_VIRTUAL = -1;
|
||||
private static final int DEFAULT_DEVICE_ID = 0;
|
||||
|
||||
private static final ScheduledExecutorService EXECUTOR = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
@@ -45,7 +45,7 @@ public class Controller {
|
||||
|
||||
MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
|
||||
coords.orientation = 0;
|
||||
coords.size = 1;
|
||||
coords.size = 0;
|
||||
|
||||
pointerProperties[i] = props;
|
||||
pointerCoords[i] = coords;
|
||||
@@ -208,9 +208,13 @@ public class Controller {
|
||||
// Right-click and middle-click only work if the source is a mouse
|
||||
boolean nonPrimaryButtonPressed = (buttons & ~MotionEvent.BUTTON_PRIMARY) != 0;
|
||||
int source = nonPrimaryButtonPressed ? InputDevice.SOURCE_MOUSE : InputDevice.SOURCE_TOUCHSCREEN;
|
||||
if (source != InputDevice.SOURCE_MOUSE) {
|
||||
// Buttons must not be set for touch events
|
||||
buttons = 0;
|
||||
}
|
||||
|
||||
MotionEvent event = MotionEvent
|
||||
.obtain(lastTouchDown, now, action, pointerCount, pointerProperties, pointerCoords, 0, buttons, 1f, 1f, DEVICE_ID_VIRTUAL, 0, source,
|
||||
.obtain(lastTouchDown, now, action, pointerCount, pointerProperties, pointerCoords, 0, buttons, 1f, 1f, DEFAULT_DEVICE_ID, 0, source,
|
||||
0);
|
||||
return device.injectEvent(event);
|
||||
}
|
||||
@@ -233,7 +237,7 @@ public class Controller {
|
||||
coords.setAxisValue(MotionEvent.AXIS_VSCROLL, vScroll);
|
||||
|
||||
MotionEvent event = MotionEvent
|
||||
.obtain(lastTouchDown, now, MotionEvent.ACTION_SCROLL, 1, pointerProperties, pointerCoords, 0, 0, 1f, 1f, DEVICE_ID_VIRTUAL, 0,
|
||||
.obtain(lastTouchDown, now, MotionEvent.ACTION_SCROLL, 1, pointerProperties, pointerCoords, 0, 0, 1f, 1f, DEFAULT_DEVICE_ID, 0,
|
||||
InputDevice.SOURCE_TOUCHSCREEN, 0);
|
||||
return device.injectEvent(event);
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ public final class Server {
|
||||
if (encoders != null && encoders.length > 0) {
|
||||
Ln.e("Try to use one of the available encoders:");
|
||||
for (MediaCodecInfo encoder : encoders) {
|
||||
Ln.e(" scrcpy --encoder-name '" + encoder.getName() + "'");
|
||||
Ln.e(" scrcpy --encoder '" + encoder.getName() + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user