Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for v4l2loopback #2233

Closed
wants to merge 1 commit into from
Closed
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
10 changes: 8 additions & 2 deletions app/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@ src = [
'src/stream.c',
'src/tiny_xpm.c',
'src/video_buffer.c',
'src/v4l2sink.c',
'src/util/net.c',
'src/util/process.c',
'src/util/str_util.c',
'src/util/thread.c',
]

conf = configuration_data()

if host_machine.system() == 'windows'
src += [ 'src/sys/win/process.c' ]
else
Expand All @@ -49,6 +52,11 @@ if not get_option('crossbuild_windows')
dependency('sdl2'),
]

if host_machine.system() == 'linux'
dependencies += dependency('libavdevice')
conf.set('V4L2SINK', '1')
endif

else

# cross-compile mingw32 build (from Linux to Windows)
Expand Down Expand Up @@ -90,8 +98,6 @@ if host_machine.system() == 'windows'
dependencies += cc.find_library('ws2_32')
endif

conf = configuration_data()

foreach f : check_functions
if cc.has_function(f)
define = 'HAVE_' + f.underscorify().to_upper()
Expand Down
25 changes: 24 additions & 1 deletion app/src/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@ scrcpy_print_usage(const char *arg0) {
" on exit.\n"
" It only shows physical touches (not clicks from scrcpy).\n"
"\n"
#ifdef V4L2SINK
" --v4l2sink /dev/videoN\n"
" Output to v4l2loopback device. It will lock video orientation. Use --lock-video-orientation to override the rotation.\n"
"\n"
#endif
" -v, --version\n"
" Print the version of scrcpy.\n"
"\n"
Expand Down Expand Up @@ -667,6 +672,7 @@ guess_record_format(const char *filename) {
#define OPT_LEGACY_PASTE 1024
#define OPT_ENCODER_NAME 1025
#define OPT_POWER_OFF_ON_CLOSE 1026
#define OPT_V4L2SINK 1027

bool
scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
Expand Down Expand Up @@ -708,6 +714,9 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
{"show-touches", no_argument, NULL, 't'},
{"stay-awake", no_argument, NULL, 'w'},
{"turn-screen-off", no_argument, NULL, 'S'},
#ifdef V4L2SINK
{"v4l2sink", required_argument, NULL, OPT_V4L2SINK},
#endif
{"verbosity", required_argument, NULL, 'V'},
{"version", no_argument, NULL, 'v'},
{"window-title", required_argument, NULL, OPT_WINDOW_TITLE},
Expand Down Expand Up @@ -890,14 +899,28 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
case OPT_POWER_OFF_ON_CLOSE:
opts->power_off_on_close = true;
break;
#ifdef V4L2SINK
case OPT_V4L2SINK:
opts->v4l2sink_device = optarg;
break;
#endif
default:
// getopt prints the error message on stderr
return false;
}
}

if (!opts->display && !opts->record_filename) {
//v4l2loopback can't handle resolution changes so we must lock video orientation in case this is used
if (opts->v4l2sink_device && opts->lock_video_orientation < 0) {
opts->lock_video_orientation = 0;
}

if (!opts->display && !opts->record_filename && !opts->v4l2sink_device) {
#ifdef V4L2SINK
LOGE("-N/--no-display requires screen recording (-r/--record) or sink to v4l2loopback device (--v4l2sink)");
#else
LOGE("-N/--no-display requires screen recording (-r/--record)");
#endif
return false;
}

Expand Down
11 changes: 11 additions & 0 deletions app/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
#include <stdbool.h>
#include <unistd.h>
#include <libavformat/avformat.h>
#ifdef V4L2SINK
#include <libavdevice/avdevice.h>
#endif
#define SDL_MAIN_HANDLED // avoid link error on Linux Windows Subsystem
#include <SDL2/SDL.h>

Expand All @@ -28,6 +31,11 @@ print_version(void) {
fprintf(stderr, " - libavutil %d.%d.%d\n", LIBAVUTIL_VERSION_MAJOR,
LIBAVUTIL_VERSION_MINOR,
LIBAVUTIL_VERSION_MICRO);
#ifdef V4L2SINK
fprintf(stderr, " - libavdevice %d.%d.%d\n", LIBAVDEVICE_VERSION_MAJOR,
LIBAVDEVICE_VERSION_MINOR,
LIBAVDEVICE_VERSION_MICRO);
#endif
}

static SDL_LogPriority
Expand Down Expand Up @@ -89,6 +97,9 @@ main(int argc, char *argv[]) {
#ifdef SCRCPY_LAVF_REQUIRES_REGISTER_ALL
av_register_all();
#endif
#ifdef V4L2SINK
avdevice_register_all();
#endif

if (avformat_network_init()) {
return 1;
Expand Down
31 changes: 30 additions & 1 deletion app/src/scrcpy.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "stream.h"
#include "tiny_xpm.h"
#include "video_buffer.h"
#include "v4l2sink.h"
#include "util/log.h"
#include "util/net.h"

Expand All @@ -38,6 +39,9 @@ static struct decoder decoder;
static struct recorder recorder;
static struct controller controller;
static struct file_handler file_handler;
#ifdef V4L2SINK
static struct v4l2sink v4l2sink;
#endif

static struct input_manager input_manager = {
.controller = &controller,
Expand Down Expand Up @@ -285,6 +289,12 @@ scrcpy(const struct scrcpy_options *options) {
bool controller_started = false;

bool record = !!options->record_filename;

#ifdef V4L2SINK
bool v4l2sink_initialized = false;
bool v4l2 = !!options->v4l2sink_device;
#endif

struct server_params params = {
.log_level = options->log_level,
.crop = options->crop,
Expand Down Expand Up @@ -363,9 +373,22 @@ scrcpy(const struct scrcpy_options *options) {
recorder_initialized = true;
}

struct v4l2sink *sink = NULL;
#ifdef V4L2SINK
if (v4l2) {
if (!v4l2sink_init(&v4l2sink,
options->v4l2sink_device,
frame_size)) {
goto end;
}
sink = &v4l2sink;
v4l2sink_initialized = true;
}
#endif

av_log_set_callback(av_log_callback);

stream_init(&stream, server.video_socket, dec, rec);
stream_init(&stream, server.video_socket, dec, rec, sink);

if (options->display) {
if (options->control) {
Expand Down Expand Up @@ -467,6 +490,12 @@ scrcpy(const struct scrcpy_options *options) {
recorder_destroy(&recorder);
}

#ifdef V4L2SINK
if (v4l2sink_initialized) {
v4l2sink_destroy(&v4l2sink);
}
#endif

if (file_handler_initialized) {
file_handler_join(&file_handler);
file_handler_destroy(&file_handler);
Expand Down
2 changes: 2 additions & 0 deletions app/src/scrcpy.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ struct scrcpy_options {
const char *render_driver;
const char *codec_options;
const char *encoder_name;
const char *v4l2sink_device;
enum sc_log_level log_level;
enum sc_record_format record_format;
struct sc_port_range port_range;
Expand Down Expand Up @@ -94,6 +95,7 @@ struct scrcpy_options {
.render_driver = NULL, \
.codec_options = NULL, \
.encoder_name = NULL, \
.v4l2sink_device = NULL, \
.log_level = SC_LOG_LEVEL_INFO, \
.record_format = SC_RECORD_FORMAT_AUTO, \
.port_range = { \
Expand Down
39 changes: 38 additions & 1 deletion app/src/stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "decoder.h"
#include "events.h"
#include "recorder.h"
#include "v4l2sink.h"
#include "util/buffer_util.h"
#include "util/log.h"

Expand Down Expand Up @@ -89,6 +90,17 @@ process_frame(struct stream *stream, AVPacket *packet) {
}
}

#ifdef V4L2SINK
if (stream->v4l2sink) {
packet->dts = packet->pts;

if (!v4l2sink_push(stream->v4l2sink, packet)) {
LOGE("Could not send packet to v4l2sink");
return false;
}
}
#endif

return true;
}

Expand Down Expand Up @@ -210,6 +222,20 @@ run_stream(void *data) {
}
}

#ifdef V4L2SINK
if (stream->v4l2sink) {
if (!v4l2sink_open(stream->v4l2sink, codec)) {
LOGE("Could not open v4l2sink");
goto finally_close_decoder;
}

if (!v4l2sink_start(stream->v4l2sink)) {
LOGE("Could not start v4l2sink");
goto finally_close_v4l2sink;
}
}
#endif

stream->parser = av_parser_init(AV_CODEC_ID_H264);
if (!stream->parser) {
LOGE("Could not initialize parser");
Expand Down Expand Up @@ -253,6 +279,16 @@ run_stream(void *data) {
if (stream->recorder) {
recorder_close(stream->recorder);
}
#ifdef V4L2SINK
finally_close_v4l2sink:
if (stream->v4l2sink) {
v4l2sink_stop(stream->v4l2sink);
LOGI("Finishing v4l2sink...");
v4l2sink_join(stream->v4l2sink);

v4l2sink_close(stream->v4l2sink);
}
#endif
finally_close_decoder:
if (stream->decoder) {
decoder_close(stream->decoder);
Expand All @@ -266,10 +302,11 @@ run_stream(void *data) {

void
stream_init(struct stream *stream, socket_t socket,
struct decoder *decoder, struct recorder *recorder) {
struct decoder *decoder, struct recorder *recorder, struct v4l2sink *v4l2sink) {
stream->socket = socket;
stream->decoder = decoder,
stream->recorder = recorder;
stream->v4l2sink = v4l2sink;
stream->has_pending = false;
}

Expand Down
3 changes: 2 additions & 1 deletion app/src/stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ struct stream {
sc_thread thread;
struct decoder *decoder;
struct recorder *recorder;
struct v4l2sink *v4l2sink;
AVCodecContext *codec_ctx;
AVCodecParserContext *parser;
// successive packets may need to be concatenated, until a non-config
Expand All @@ -28,7 +29,7 @@ struct stream {

void
stream_init(struct stream *stream, socket_t socket,
struct decoder *decoder, struct recorder *recorder);
struct decoder *decoder, struct recorder *recorder, struct v4l2sink *v4l2sink);

bool
stream_start(struct stream *stream);
Expand Down
Loading