From f7944b7d9396e4b2a31aa8615ceb2ea3ed81359d Mon Sep 17 00:00:00 2001 From: skbeh <60107333+skbeh@users.noreply.github.com> Date: Wed, 5 Oct 2022 16:56:03 +0800 Subject: [PATCH] fix some issues 1. Automatically detect libturbojpeg linking arguments. 2. Fixed a data race with `a_running` and `v_running` when exiting. 3. Automatically try next v4l2 dev when failing to set pixel format. --- .gitignore | 3 ++- Makefile | 14 ++++---------- src/av.c | 14 +++++++------- src/connection.c | 8 +++++--- src/connection.h | 2 +- src/decoder.c | 11 ++--------- src/decoder.h | 4 ++-- src/decoder_snd.c | 11 ++++++----- src/decoder_v4l2.c | 16 ++++++++++++++-- src/droidcam-cli.c | 22 ++++++++++++---------- src/droidcam.c | 18 ++++++++++-------- v4l2loopback/test.c | 2 +- 12 files changed, 66 insertions(+), 59 deletions(-) diff --git a/.gitignore b/.gitignore index 63a7bb0..05cfb4a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ -droidcam* +/droidcam +/droidcam-cli # vim swap files *.swp diff --git a/Makefile b/Makefile index b372b09..ea95271 100644 --- a/Makefile +++ b/Makefile @@ -6,26 +6,20 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # Use at your own risk. See README file for more details. -# # Variables with ?= can be changed during invocation # Example: # APPINDICATOR=ayatana-appindicator3-0.1 make droidcam APPINDICATOR ?= appindicator3-0.1 -JPEG_DIR ?= /opt/libjpeg-turbo -JPEG_INCLUDE ?= $(JPEG_DIR)/include -JPEG_LIB ?= $(JPEG_DIR)/lib`getconf LONG_BIT` - +CFLAGS ?= -Wall -O2 -CC = gcc -CFLAGS = -Wall -O2 GTK = `pkg-config --libs --cflags gtk+-3.0` `pkg-config --libs x11` GTK += `pkg-config --libs --cflags $(APPINDICATOR)` LIBAV = `pkg-config --libs --cflags libswscale libavutil` -LIBS = -lspeex -lasound -lpthread -lm -JPEG = -I$(JPEG_INCLUDE) $(JPEG_LIB)/libturbojpeg.a +LIBS = -lspeex -lasound -lpthread -lm +JPEG = `pkg-config --libs --cflags libturbojpeg` SRC = src/connection.c src/settings.c src/decoder*.c src/av.c src/usb.c src/queue.c -USBMUXD = -lusbmuxd +USBMUXD = `pkg-config --libs --cflags libusbmuxd-2.0` ifneq ($(findstring ayatana,$(APPINDICATOR)),) CFLAGS += -DUSE_AYATANA_APPINDICATOR diff --git a/src/av.c b/src/av.c index d9c6444..851c99f 100644 --- a/src/av.c +++ b/src/av.c @@ -10,17 +10,18 @@ #include "settings.h" #include "connection.h" #include "decoder.h" +#include #include -extern int a_running; -extern int v_running; -extern int thread_cmd; +extern atomic_bool a_running; +extern atomic_bool v_running; +extern char thread_cmd; extern struct settings g_settings; const char *thread_cmd_val_str; SOCKET GetConnection(void) { - char *err; + const char *err; SOCKET socket = INVALID_SOCKET; if (g_settings.connection == CB_RADIO_IOS) { @@ -91,7 +92,7 @@ void *BatteryThreadProc(__attribute__((__unused__)) void *args) { void *DecodeThreadProc(__attribute__((__unused__)) void *args) { dbgprint("Decode Thread Start\n"); - while (v_running != 0) { + while (v_running) { JPGFrame *f = pull_ready_jpg_frame(); if (!f) { usleep(2000); @@ -134,9 +135,8 @@ void *VideoThreadProc(void *args) { goto early_out; } - while (v_running != 0){ + while (v_running){ if (thread_cmd != 0) { - len = 0; if (thread_cmd == CB_CONTROL_WB) { len = snprintf(buf, sizeof(buf), OTHER_REQ_STR, thread_cmd, thread_cmd_val_str); } diff --git a/src/connection.c b/src/connection.c index 10f0aff..5a923f5 100644 --- a/src/connection.c +++ b/src/connection.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include @@ -20,14 +22,14 @@ #include "connection.h" SOCKET wifiServerSocket = INVALID_SOCKET; -extern int v_running; +extern atomic_bool v_running; -char* DROIDCAM_CONNECT_ERROR = \ +const char* DROIDCAM_CONNECT_ERROR = \ "Connect failed, please try again.\n" "Check IP and Port.\n" "Check network connection.\n"; -SOCKET Connect(const char* ip, int port, char **errormsg) { +SOCKET Connect(const char* ip, int port, const char **errormsg) { int flags; struct sockaddr_in sin; SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); diff --git a/src/connection.h b/src/connection.h index e61eb63..37a2668 100644 --- a/src/connection.h +++ b/src/connection.h @@ -13,7 +13,7 @@ typedef int SOCKET; typedef long int SOCKET_PTR; -SOCKET Connect(const char* ip, int port, char **errormsg); +SOCKET Connect(const char* ip, int port, const char **errormsg); void connection_cleanup(); void disconnect(SOCKET s); diff --git a/src/decoder.c b/src/decoder.c index 5c72ceb..e6613e4 100644 --- a/src/decoder.c +++ b/src/decoder.c @@ -93,10 +93,10 @@ int decoder_init(const char* v4l2_device, unsigned v4l2_width, unsigned v4l2_hei set_v4l2_device(v4l2_device); droidcam_device_fd = open_v4l2_device(); } else { - droidcam_device_fd = find_v4l2_device("platform:v4l2loopback_dc"); + droidcam_device_fd = find_v4l2_device("platform:v4l2loopback_dc", &WEBCAM_W, &WEBCAM_H); if (droidcam_device_fd < 0) { // check for generic v4l2loopback device - droidcam_device_fd = find_v4l2_device("platform:v4l2loopback"); + droidcam_device_fd = find_v4l2_device("platform:v4l2loopback", &WEBCAM_W, &WEBCAM_H); } } @@ -108,13 +108,6 @@ int decoder_init(const char* v4l2_device, unsigned v4l2_width, unsigned v4l2_hei WEBCAM_W = 320; WEBCAM_H = 240; droidcam_device_fd = 0; - } else { - query_v4l_device(droidcam_device_fd, &WEBCAM_W, &WEBCAM_H); - dbgprint("WEBCAM_W=%d, WEBCAM_H=%d\n", WEBCAM_W, WEBCAM_H); - if (WEBCAM_W < 2 || WEBCAM_H < 2 || WEBCAM_W > 9999 || WEBCAM_H > 9999){ - MSG_ERROR("Unable to query v4l2 device for correct parameters"); - return 0; - } } memset(&jpg_decoder, 0, sizeof(struct jpg_dec_ctx_s)); diff --git a/src/decoder.h b/src/decoder.h index 646776d..d675aa2 100644 --- a/src/decoder.h +++ b/src/decoder.h @@ -47,7 +47,7 @@ int decoder_horizontal_flip(); int decoder_vertical_flip(); void decoder_show_test_image(); -/* 20ms 16hkz 16 bit */ +/* 20ms 16khz 16 bit */ #define DROIDCAM_CHUNK_MS_2 20 #define DROIDCAM_SPX_CHUNK_BYTES_2 70 #define DROIDCAM_PCM_CHUNK_BYTES_2 640 @@ -65,7 +65,7 @@ void decoder_show_test_image(); void set_v4l2_device(const char* device); int open_v4l2_device(void); -int find_v4l2_device(const char* bus_info); +int find_v4l2_device(const char* bus_info, unsigned *in_v4l2_width, unsigned *in_v4l2_height); void query_v4l_device(int droidcam_device_fd, unsigned *WEBCAM_W, unsigned *WEBCAM_H); snd_pcm_t *find_snd_device(void); diff --git a/src/decoder_snd.c b/src/decoder_snd.c index fef0408..2f995f7 100644 --- a/src/decoder_snd.c +++ b/src/decoder_snd.c @@ -24,14 +24,12 @@ static snd_pcm_sframes_t period_size; static unsigned int period_time = PERIOD_TIME;/* period time in us */ static unsigned int buffer_time = DROIDCAM_SPEEX_BACKBUF_MAX_COUNT * PERIOD_TIME; /* ring buffer length in us */ -snd_pcm_hw_params_t *hwparams; -snd_pcm_sw_params_t *swparams; - static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access) { unsigned int rrate; snd_pcm_uframes_t size; - int err, dir; - int resample = 1; + int err; + int dir = 0; + const unsigned int resample = 1; /* choose all parameters */ err = snd_pcm_hw_params_any(handle, params); if (err < 0) { @@ -248,6 +246,9 @@ int snd_transfer_commit(snd_pcm_t *handle, struct snd_transfer_s *transfer) { snd_pcm_t *find_snd_device(void) { int err, card, i; snd_pcm_t *handle = NULL; + snd_pcm_hw_params_t *hwparams; + snd_pcm_sw_params_t *swparams; + snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); diff --git a/src/decoder_v4l2.c b/src/decoder_v4l2.c index bea3b98..13fd3cc 100644 --- a/src/decoder_v4l2.c +++ b/src/decoder_v4l2.c @@ -32,7 +32,7 @@ int open_v4l2_device(void) { if (!S_ISCHR(st.st_mode)) return 0; - fd = open(v4l2_device, O_RDWR | O_NONBLOCK, 0); + fd = open(v4l2_device, O_WRONLY | O_NONBLOCK, 0); if (fd <= 0) { errprint("Error opening '%s': %d '%s'\n", v4l2_device, errno, strerror(errno)); return 0; @@ -42,7 +42,7 @@ int open_v4l2_device(void) { return fd; } -int find_v4l2_device(const char* bus_info) { +int find_v4l2_device(const char* bus_info, unsigned *in_v4l2_width, unsigned *in_v4l2_height) { int bus_info_len = strlen(bus_info); int video_dev_fd; int video_dev_nr = 0; @@ -50,6 +50,9 @@ int find_v4l2_device(const char* bus_info) { dbgprint("Looking for v4l2 card: %s\n", bus_info); for (video_dev_nr = 0; video_dev_nr < 99; video_dev_nr++) { + unsigned v4l2_width = *in_v4l2_width; + unsigned v4l2_height = *in_v4l2_height; + snprintf(v4l2_device, sizeof(v4l2_device), "/dev/video%d", video_dev_nr); video_dev_fd = open_v4l2_device(); @@ -61,8 +64,17 @@ int find_v4l2_device(const char* bus_info) { continue; } + query_v4l_device(video_dev_fd, &v4l2_width, &v4l2_height) dbgprint("Device %s is '%s' @ %s\n", v4l2_device, v4l2cap.card, v4l2cap.bus_info); + dbgprint("v4l2_width=%d, v4l2_height=%d\n", v4l2_width, v4l2_height); + if (v4l2_width < 2 || v4l2_height < 2 || v4l2_width > 9999 || v4l2_height > 9999){ + errprint("Unable to query v4l2 device for correct parameters\n"); + continue; + } + if (0 == strncmp(bus_info, (const char*) v4l2cap.bus_info, bus_info_len)) { + *in_v4l2_width = v4l2_width; + *in_v4l2_height = v4l2_height; return video_dev_fd; } diff --git a/src/droidcam-cli.c b/src/droidcam-cli.c index c974bc1..9c5ad0c 100644 --- a/src/droidcam-cli.c +++ b/src/droidcam-cli.c @@ -8,6 +8,8 @@ #include #include +#include +#include #include "common.h" #include "settings.h" @@ -23,9 +25,9 @@ Thread athread = {0, -1}, vthread = {0, -1}, dthread = {0, -1}; char *v4l2_dev = 0; unsigned v4l2_width = 0, v4l2_height = 0; -int v_running = 0; -int a_running = 0; -int thread_cmd = 0; +atomic_bool a_running = false; +atomic_bool v_running = false; +char thread_cmd = 0; int no_controls = 0; struct settings g_settings = {0}; @@ -37,8 +39,8 @@ void * VideoThreadProc(void * args); void * DecodeThreadProc(void * args); void sig_handler(__attribute__((__unused__)) int sig) { - a_running = 0; - v_running = 0; + a_running = false; + v_running = false; return; } @@ -111,7 +113,7 @@ static void parse_args(int argc, char *argv[]) { continue; } if (argv[i][0] == '-' && argv[i][1] == 'v') { - v_running = 1; + v_running = true; continue; } @@ -140,8 +142,8 @@ static void parse_args(int argc, char *argv[]) { if (argv[i][0] == '-' && argv[i][1] == 'l') { g_settings.port = strtoul(argv[i+1], NULL, 10); g_settings.connection = CB_WIFI_SRVR; - a_running = 0; - v_running = 1; + a_running = false; + v_running = true; return; } @@ -233,7 +235,7 @@ int main(int argc, char *argv[]) { parse_args(argc, argv); if (!v_running && !a_running) - v_running = 1; + v_running = true; if (!decoder_init(v4l2_dev, v4l2_width, v4l2_height)) { return 2; @@ -262,7 +264,7 @@ int main(int argc, char *argv[]) { videoSocket = rc; } else { - char *errmsg = NULL; + const char *errmsg = NULL; videoSocket = Connect(g_settings.ip, g_settings.port, &errmsg); if (videoSocket == INVALID_SOCKET) { errprint("Video: Connect failed to %s:%d\n", g_settings.ip, g_settings.port); diff --git a/src/droidcam.c b/src/droidcam.c index b8e93cf..9a466b6 100644 --- a/src/droidcam.c +++ b/src/droidcam.c @@ -14,6 +14,8 @@ #endif #include +#include +#include #include #include "common.h" @@ -40,9 +42,9 @@ GThread* hDecodeThread; GThread* hBatteryThread; char *v4l2_dev = 0; -int a_running = 0; -int v_running = 0; -int thread_cmd = 0; +atomic_bool a_running = false; +atomic_bool v_running = false; +char thread_cmd = 0; struct settings g_settings = {0}; extern const char *thread_cmd_val_str; @@ -104,8 +106,8 @@ void UpdateBatteryLabel(char *battery_value) { } static void Stop(void) { - a_running = 0; - v_running = 0; + a_running = false; + v_running = false; dbgprint("join\n"); if (hVideoThread) { g_thread_join(hVideoThread); @@ -142,7 +144,7 @@ static void Start(void) { g_settings.port = port; if (g_settings.connection == CB_WIFI_SRVR) { - v_running = 1; + v_running = true; hVideoThread = g_thread_new(NULL, VideoThreadProc, (void*) (SOCKET_PTR) s); hDecodeThread = g_thread_new(NULL, DecodeThreadProc, NULL); goto EARLY_OUT; @@ -181,7 +183,7 @@ static void Start(void) { return; } - char *errmsg = NULL; + const char *errmsg = NULL; gtk_button_set_label(start_button, "Please wait"); s = Connect(ip, port, &errmsg); if (s == INVALID_SOCKET) { @@ -194,7 +196,7 @@ static void Start(void) { } if (g_settings.video) { - v_running = 1; + v_running = true; hVideoThread = g_thread_new(NULL, VideoThreadProc, (void*) (SOCKET_PTR) s); hDecodeThread = g_thread_new(NULL, DecodeThreadProc, NULL); } else { diff --git a/v4l2loopback/test.c b/v4l2loopback/test.c index e780826..f985bb3 100644 --- a/v4l2loopback/test.c +++ b/v4l2loopback/test.c @@ -112,7 +112,7 @@ int main(int argc, char**argv) printf("using output device: %s\n", video_device); } - fdwr = open(video_device, O_RDWR); + fdwr = open(video_device, O_WRONLY); assert(fdwr >= 0); ret_code = ioctl(fdwr, VIDIOC_QUERYCAP, &vid_caps);