From c9deef0f62b271c1831211dc438fb82ee8007045 Mon Sep 17 00:00:00 2001 From: gozfree Date: Mon, 16 May 2022 00:26:05 +0800 Subject: [PATCH] 1.remove libuvc and libuac, replace with libavcap 2.update libbitmap from kernel 3.update libstrex --- README.cn.md | 2 +- README.md | 2 +- build.sh | 2 +- gear-lib/CMakeLists.txt | 3 +- gear-lib/component.mk | 8 +- gear-lib/libavcap/Makefile.nmake | 15 +- gear-lib/libavcap/README.md | 97 ++- gear-lib/libavcap/esp32-camera.c | 171 ++++ gear-lib/libbitmap/bitops.h | 17 + gear-lib/libbitmap/kernel.h | 36 +- gear-lib/libbitmap/libbitmap.c | 1161 ++++++++++++++++++++++++- gear-lib/libbitmap/libbitmap.h | 496 +++++++++-- gear-lib/librtsp/CMakeLists.txt | 2 +- gear-lib/librtsp/media_source_live.c | 58 +- gear-lib/libstrex/libstrex.c | 16 + gear-lib/libstrex/libstrex.h | 1 + gear-lib/libuac/Android.mk | 18 - gear-lib/libuac/Makefile | 106 --- gear-lib/libuac/Makefile.nmake | 54 -- gear-lib/libuac/README.md | 5 - gear-lib/libuac/libuac.c | 102 --- gear-lib/libuac/libuac.h | 85 -- gear-lib/libuac/pulseaudio.c | 733 ---------------- gear-lib/libuac/test_libuac.c | 73 -- gear-lib/libuvc/Android.mk | 18 - gear-lib/libuvc/CMakeLists.txt | 14 - gear-lib/libuvc/Makefile | 107 --- gear-lib/libuvc/Makefile.nmake | 54 -- gear-lib/libuvc/README.md | 99 --- gear-lib/libuvc/dshow.c | 1177 -------------------------- gear-lib/libuvc/dshow.h | 245 ------ gear-lib/libuvc/dummy.c | 339 -------- gear-lib/libuvc/libuvc.c | 165 ---- gear-lib/libuvc/libuvc.h | 127 --- gear-lib/libuvc/test_libuvc.c | 134 --- gear-lib/libuvc/usbcam.c | 1123 ------------------------ gear-lib/libuvc/usbcam.h | 458 ---------- gear-lib/libuvc/v4l2.c | 1013 ---------------------- 38 files changed, 1907 insertions(+), 6429 deletions(-) create mode 100644 gear-lib/libavcap/esp32-camera.c delete mode 100644 gear-lib/libuac/Android.mk delete mode 100644 gear-lib/libuac/Makefile delete mode 100644 gear-lib/libuac/Makefile.nmake delete mode 100644 gear-lib/libuac/README.md delete mode 100644 gear-lib/libuac/libuac.c delete mode 100644 gear-lib/libuac/libuac.h delete mode 100644 gear-lib/libuac/pulseaudio.c delete mode 100644 gear-lib/libuac/test_libuac.c delete mode 100644 gear-lib/libuvc/Android.mk delete mode 100644 gear-lib/libuvc/CMakeLists.txt delete mode 100644 gear-lib/libuvc/Makefile delete mode 100644 gear-lib/libuvc/Makefile.nmake delete mode 100644 gear-lib/libuvc/README.md delete mode 100644 gear-lib/libuvc/dshow.c delete mode 100644 gear-lib/libuvc/dshow.h delete mode 100644 gear-lib/libuvc/dummy.c delete mode 100644 gear-lib/libuvc/libuvc.c delete mode 100644 gear-lib/libuvc/libuvc.h delete mode 100644 gear-lib/libuvc/test_libuvc.c delete mode 100644 gear-lib/libuvc/usbcam.c delete mode 100644 gear-lib/libuvc/usbcam.h delete mode 100644 gear-lib/libuvc/v4l2.c diff --git a/README.cn.md b/README.cn.md index 2611420..e54b9dd 100644 --- a/README.cn.md +++ b/README.cn.md @@ -44,7 +44,7 @@ ## 多媒体 | | | |--|--| -| libuvc: USB摄像头库 | libmp4: MP4录制解析库 | +| libavcap: 音频视频捕获库 | libmp4: MP4录制解析库 | | libjpeg-ex: | libmedia-io: 音频视频格式定义 | ## 系统抽象层 diff --git a/README.md b/README.md index 6ff57a4..30935d2 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ This is a collection of basic libraries. ## Multi-Media | | | |--|--| -| libuvc: USB video class V4L2/dshow | libmp4: MP4 muxer and parser | +| libavcap: audio/video capture api (v4l2/uvc/esp32/dshow) | libmp4: MP4 muxer and parser | | libjpeg-ex: | libmedia-io: audio/video frame/packet define | ## OS Abstraction Layer diff --git a/build.sh b/build.sh index 00758fd..415eadf 100755 --- a/build.sh +++ b/build.sh @@ -26,7 +26,7 @@ PLATFORM="[linux|pi|android|ios]" #basic libraries BASIC_LIBS="libposix libtime liblog libdarray libthread libgevent libworkq libdict libhash libsort \ - librbtree libringbuffer libvector libbase64 libmedia-io \ + librbtree libringbuffer libvector libstrex libmedia-io \ libdebug libfile libqueue libplugin libhal libsubmask" MEDIA_LIBS="libavcap" FRAMEWORK_LIBS="libipc" diff --git a/gear-lib/CMakeLists.txt b/gear-lib/CMakeLists.txt index 3f31687..6bb75ba 100644 --- a/gear-lib/CMakeLists.txt +++ b/gear-lib/CMakeLists.txt @@ -22,7 +22,7 @@ SET(QUEUE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libqueue/) SET(LOG_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/liblog/) SET(SOCK_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libsock/) SET(FILE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libfile/) -SET(UVC_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libuvc/) +SET(AVCAP_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libavcap/) SET(TIME_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libtime/) ADD_SUBDIRECTORY(libposix) @@ -39,6 +39,5 @@ ADD_SUBDIRECTORY(libsock) ADD_SUBDIRECTORY(liblog) ADD_SUBDIRECTORY(libmedia-io) ADD_SUBDIRECTORY(libavcap) -ADD_SUBDIRECTORY(libuvc) ADD_SUBDIRECTORY(librtmpc) ADD_SUBDIRECTORY(librtsp) diff --git a/gear-lib/component.mk b/gear-lib/component.mk index c9334a1..8c54c92 100644 --- a/gear-lib/component.mk +++ b/gear-lib/component.mk @@ -1,11 +1,13 @@ -COMPONENT_ADD_INCLUDEDIRS = . ./libposix ./libthread ./libdarray ./libmedia-io ./libqueue ./liblog ./libavcap ./libfile ./libhal -COMPONENT_SRCDIRS = libposix liblog libdarray libqueue libthread libmedia-io librtmpc libgevent libavcap libfile libhal +COMPONENT_ADD_INCLUDEDIRS = . ./libposix ./libthread ./libdarray ./libmedia-io ./libqueue ./liblog ./libavcap ./libfile ./libhal ./librbtree +COMPONENT_SRCDIRS = libposix liblog libdarray libqueue libthread libmedia-io librtmpc libgevent libavcap libfile libhal librbtree COMPONENT_OBJEXCLUDE = libposix/libposix4win.o libposix/libposix4nix.o libposix/libposix4rtthread.o libposix/test_libposix.o \ libavcap/dshow.o libavcap/xcbgrab.o libavcap/v4l2.o libavcap/test_libavcap.o libavcap/pulseaudio.o libavcap/uvc.o \ libfile/test_libfile.o libfile/filewatcher.o \ libdarray/test_libdarray.o libqueue/test_libqueue.o libthread/test_libthread.o libmedia-io/test_libmedia-io.o \ librtmpc/test_librtmpc.o liblog/test_liblog.o libgevent/iocp.o libgevent/epoll.o libgevent/wepoll.o \ - libhal/hal_nix.o libhal/hal_win.o libhal/test_hal.o + libhal/hal_nix.o libhal/hal_win.o libhal/test_hal.o \ + librbtree/test_librbtree.o + COMPONENT_DEPENDS := newlib CFLAGS += -DFREERTOS -DESP32 #for libposix CFLAGS += -DNO_CRYPTO #for librtmpc diff --git a/gear-lib/libavcap/Makefile.nmake b/gear-lib/libavcap/Makefile.nmake index a8a13bd..b18e48c 100644 --- a/gear-lib/libavcap/Makefile.nmake +++ b/gear-lib/libavcap/Makefile.nmake @@ -13,22 +13,21 @@ TGT_LIB_A = $(LIBNAME).lib TGT_LIB_SO = $(LIBNAME).dll TGT_UNIT_TEST = test_$(LIBNAME).exe -OBJS_LIB = $(LIBNAME).obj +OBJS_LIB = $(LIBNAME).obj dshow.obj OBJS_UNIT_TEST = test_$(LIBNAME).obj ############################################################################### # cflags and ldflags ############################################################################### -CFLAGS = /Iinclude /I. +CFLAGS = /I../libposix/ /I../libmedia-io/ /I../libfile/ /I. !IF "$(MODE)"=="release" CFLAGS = $(CFLAGS) /O2 /GF !ELSE CFLAGS = $(CFLAGS) /Od /W3 /Zi !ENDIF -LDFLAGS = /NOLOGO - -LIBS = ws2_32.lib +LIBS = ole32.lib strmiids.lib uuid.lib oleaut32.lib shlwapi.lib \ + ../libmedia-io/libmedia-io.lib ../libfile/libfile.lib ../libposix/libposix.lib ############################################################################### # target @@ -40,13 +39,13 @@ OBJS = $(OBJS_LIB) $(OBJS_UNIT_TEST) all: $(TGT) $(TGT_LIB_A): $(OBJS_LIB) - $(AR) $(OBJS_LIB) $(LIBS) /o:$(TGT_LIB_A) + $(AR) $(OBJS_LIB) $(LIBS) /out:$(TGT_LIB_A) $(TGT_LIB_SO): $(OBJS_LIB) - $(LD) $(LDFLAGS) /Dll $(OBJS_LIB) $(LIBS) /o:$(TGT_LIB_SO) + $(LD) /Dll $(OBJS_LIB) $(LIBS) $(TGT_UNIT_TEST): $(OBJS_UNIT_TEST) - $(CC) $(TGT_LIB_A) $(OBJS_UNIT_TEST) /o $(TGT_UNIT_TEST) + $(CC) $(TGT_LIB_A) $(OBJS_UNIT_TEST) /link $(LIBS) clean: $(RM) $(OBJS) diff --git a/gear-lib/libavcap/README.md b/gear-lib/libavcap/README.md index 042e26f..9804eec 100644 --- a/gear-lib/libavcap/README.md +++ b/gear-lib/libavcap/README.md @@ -2,12 +2,14 @@ This is a simple audio video capture library. It's aim is to provide a unified API for Linux, Windows and Mac OS X to capture audio and video from appropriate hardware. The supported hardware contain Webcam, RaspberryPi, Laptop Camera which based onUVC. +refer to https://sourceforge.net/projects/libavcap/ ### Video -* uvc: USB Video Class +* uvc: USB Video Class (depend on libuvc https://github.com/ktossell/libuvc) * v4l2: video for linux * dshow: windows video api * dummy: file of frame sequence, as virtual device +* esp32-camera: ESP32 camera (https://github.com/espressif/esp32-camera.git) * xcb: linux desktop screen capture, XCB(X protocol C-language Binding) ### Audio @@ -15,6 +17,99 @@ The supported hardware contain Webcam, RaspberryPi, Laptop Camera which based on #### Test * ffplay -f rawvideo -pixel_format yuyv422 -video_size 640x480 v4l2.yuv +* ffplay -f rawvideo -pixel_format yuv420p -video_size 640x480 v4l2.yuv (raspberry pi) * ffplay -ar 48000 -channels 2 -f s16le -i pulseaudio.pcm * ffplay -f x11grab -i :0.0 +* ffplay -pix_fmts * ffmpeg -f x11grab -framerate 25 -video_size 1366*768 -i :0.0 out.mp4 + +# raspberry pi +`$ sudo modprobe bcm2835_v4l2 ` + +``` +x86 $ ./test_libavcap +[V4L2 Input information]: + input.name: "Camera 1" +[V4L2 Capability Information]: + cap.driver: "uvcvideo" + cap.card: "Lenovo EasyCamera: Lenovo EasyC" + cap.bus_info: "usb-0000:00:1d.0-1.6" + cap.version: "266002" + cap.capabilities: + VIDEO_CAPTURE + STREAMING +[V4L2 Support Format]: + 0. [YUYV] "YUYV 4:2:2" + 1. [MJPG] "Motion-JPEG" +[V4L2 Supported Control]: + Brightness, range: [-64, 64], default: 0, current: 0 + Contrast, range: [0, 64], default: 32, current: 32 + Saturation, range: [0, 128], default: 64, current: 64 + Hue, range: [-180, 180], default: 0, current: 0 + White Balance Temperature, Auto, range: [0, 1], default: 1, current: 1 + Gamma, range: [100, 500], default: 300, current: 300 + Power Line Frequency, range: [0, 2], default: 1, current: 1 + White Balance Temperature, range: [2800, 6500], default: 4650, current: 4650 + Sharpness, range: [0, 8], default: 6, current: 6 + Backlight Compensation, range: [0, 2], default: 0, current: 0 +``` + + +``` +raspberrypi0w $ ./test_libavcap +[V4L2 Input information]: + input.name: "Camera 0" +[V4L2 Capability Information]: + cap.driver: "bm2835 mmal" + cap.card: "mmal service 16.1" + cap.bus_info: "platform:bcm2835-v4l2" + cap.version: "265799" + cap.capabilities: + VIDEO_CAPTURE + VIDEO_OVERLAY + READWRITE + STREAMING +[V4L2 Support Format]: + 0. [YU12] "Planar YUV 4:2:0" + 1. [YUYV] "YUYV 4:2:2" + 2. [RGB3] "24-bit RGB 8-8-8" + 3. [JPEG] "JFIF JPEG" + 4. [H264] "H.264" + 5. [MJPG] "Motion-JPEG" + 6. [YVYU] "YVYU 4:2:2" + 7. [VYUY] "VYUY 4:2:2" + 8. [UYVY] "UYVY 4:2:2" + 9. [NV12] "Y/CbCr 4:2:0" + 10. [BGR3] "24-bit BGR 8-8-8" + 11. [YV12] "Planar YVU 4:2:0" + 12. [NV21] "Y/CrCb 4:2:0" + 13. [BGR4] "32-bit BGRA/X 8-8-8-8" +[V4L2 Supported Control]: + Brightness, range: [0, 100], default: 50, current: 50 + Contrast, range: [-100, 100], default: 0, current: 0 + Saturation, range: [-100, 100], default: 0, current: 0 + Power Line Frequency, range: [0, 3], default: 1, current: 1 + Sharpness, range: [-100, 100], default: 0, current: 0 +``` + + +``` +raspberrypi2b $ ./test_libavcap +[V4L2 Input information]: + input.name: "Camera 0" +[V4L2 Capability Information]: + cap.driver: "unicam" + cap.card: "unicam" + cap.bus_info: "platform:3f801000.csi" + cap.version: "330303" + cap.capabilities: + VIDEO_CAPTURE + READWRITE + STREAMING +[V4L2 Support Format]: + 0. [BA81] "8-bit Bayer BGBG/GRGR" + 1. [pBAA] "10-bit Bayer BGBG/GRGR Packed" + 2. [BG10] "10-bit Bayer BGBG/GRGR" +[V4L2 Supported Control]: + White Balance, Automatic, range: [0, 1], default: 0, current: 0 +``` diff --git a/gear-lib/libavcap/esp32-camera.c b/gear-lib/libavcap/esp32-camera.c new file mode 100644 index 0000000..2892500 --- /dev/null +++ b/gear-lib/libavcap/esp32-camera.c @@ -0,0 +1,171 @@ +#include "libavcap.h" +#include +#include +#include +#include + +#define CONFIG_CAMERA_MODEL_ESP_EYE 1 + +#if CONFIG_CAMERA_MODEL_ESP_EYE +#define CAMERA_PIN_PWDN -1 +#define CAMERA_PIN_RESET -1 +#define CAMERA_PIN_SIOD 18 +#define CAMERA_PIN_SIOC 23 +#define CAMERA_PIN_XCLK 4 + +#define CAMERA_PIN_D0 34 +#define CAMERA_PIN_D1 13 +#define CAMERA_PIN_D2 14 +#define CAMERA_PIN_D3 35 +#define CAMERA_PIN_D4 39 +#define CAMERA_PIN_D5 38 +#define CAMERA_PIN_D6 37 +#define CAMERA_PIN_D7 36 +#define CAMERA_PIN_VSYNC 5 +#define CAMERA_PIN_HREF 27 +#define CAMERA_PIN_PCLK 25 +#endif + +#define CAMERA_FRAME_SIZE FRAMESIZE_VGA +#define CAMERA_WIDTH 640 +#define CAMERA_HEIGHT 480 + +struct esp32_cam_ctx { + camera_config_t conf; + camera_fb_t *fb; + struct thread *thread; + bool is_streaming; +}; + +static camera_config_t default_camera_config = { + .ledc_channel = LEDC_CHANNEL_0, + .ledc_timer = LEDC_TIMER_0, + .pin_d0 = CAMERA_PIN_D0, + .pin_d1 = CAMERA_PIN_D1, + .pin_d2 = CAMERA_PIN_D2, + .pin_d3 = CAMERA_PIN_D3, + .pin_d4 = CAMERA_PIN_D4, + .pin_d5 = CAMERA_PIN_D5, + .pin_d6 = CAMERA_PIN_D6, + .pin_d7 = CAMERA_PIN_D7, + .pin_xclk = CAMERA_PIN_XCLK, + .pin_pclk = CAMERA_PIN_PCLK, + .pin_vsync = CAMERA_PIN_VSYNC, + .pin_href = CAMERA_PIN_HREF, + .pin_sscb_sda = CAMERA_PIN_SIOD, + .pin_sscb_scl = CAMERA_PIN_SIOC, + .pin_pwdn = CAMERA_PIN_PWDN, + .pin_reset = CAMERA_PIN_RESET, + .xclk_freq_hz = CONFIG_XCLK_FREQ, + + .frame_size = CAMERA_FRAME_SIZE, + .pixel_format = PIXFORMAT_JPEG, + .jpeg_quality = 15, + + .fb_count = 2, + }; + +static void *cam_open(struct avcap_ctx *avcap, const char *dev, struct avcap_config *avconf) +{ + struct esp32_cam_ctx *c = calloc(1, sizeof(struct esp32_cam_ctx)); + if (!c) { + printf("malloc esp32_cam_ctx failed!\n"); + return NULL; + } + memcpy(&c->conf, &default_camera_config, sizeof(camera_config_t)); + + /* IO13, IO14 is designed for JTAG by default, + * to use it as generalized input, + * firstly declair it as pullup input */ + gpio_config_t conf; + conf.mode = GPIO_MODE_INPUT; + conf.pull_up_en = GPIO_PULLUP_ENABLE; + conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + conf.intr_type = GPIO_INTR_DISABLE; + conf.pin_bit_mask = 1LL << 13; + gpio_config(&conf); + conf.pin_bit_mask = 1LL << 14; + gpio_config(&conf); + + esp_err_t err = esp_camera_init(&c->conf); + if (err != ESP_OK) { + printf("Camera init failed with error 0x%x", err); + return NULL; + } + + memcpy(&avcap->conf, avconf, sizeof(struct avcap_config)); + return c; +} + +static void cam_close(struct avcap_ctx *avcap) +{ + struct esp32_cam_ctx *c = (struct esp32_cam_ctx *)avcap->opaque; + if (esp_camera_deinit() != ESP_OK) { + printf("esp_camera_deinit failed!\n"); + } + free(c); +} + +static void *cam_thread(struct thread *t, void *arg) +{ + struct avcap_ctx *avcap = arg; + struct esp32_cam_ctx *c = (struct esp32_cam_ctx *)avcap->opaque; + struct media_frame media; + struct video_frame *frame = &media.video; + media.type = MEDIA_TYPE_VIDEO; + + video_frame_init(frame, avcap->conf.video.format, avcap->conf.video.width, + avcap->conf.video.height, MEDIA_MEM_DEEP); + c->is_streaming = true; + while (c->is_streaming) { + c->fb = esp_camera_fb_get(); + if (!c->fb) { + printf("Camera capture failed"); + return NULL; + } + printf("Camera capture width=%d, height=%d size=%d\n", + c->fb->width, c->fb->height, c->fb->len); + avcap->on_media_frame(avcap, &media); + esp_camera_fb_return(c->fb); + } + return NULL; +} + +static int cam_start_stream(struct avcap_ctx *avcap) +{ + struct esp32_cam_ctx *c = (struct esp32_cam_ctx *)avcap->opaque; + + if (avcap->on_media_frame) { + c->thread = thread_create(cam_thread, avcap); + if (!c->thread) { + printf("thread_create failed!\n"); + return -1; + } + } + + return 0; +} + +static int cam_stop_stream(struct avcap_ctx *avcap) +{ + struct esp32_cam_ctx *c = (struct esp32_cam_ctx *)avcap->opaque; + if (!c->is_streaming) { + printf("esp32 stream stopped already!\n"); + return -1; + } + + if (avcap->on_media_frame) { + c->is_streaming = false; + thread_join(c->thread); + thread_destroy(c->thread); + } + return 0; +} + +struct avcap_ops esp32cam_ops = { + ._open = cam_open, + ._close = cam_close, + .ioctl = NULL, + .start_stream = cam_start_stream, + .stop_stream = cam_stop_stream, +}; diff --git a/gear-lib/libbitmap/bitops.h b/gear-lib/libbitmap/bitops.h index 65caff5..1333316 100644 --- a/gear-lib/libbitmap/bitops.h +++ b/gear-lib/libbitmap/bitops.h @@ -5,6 +5,23 @@ #include #include "kernel.h" //#include +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#ifdef __GNUC__ +__extension__ typedef __signed__ long long __s64; +__extension__ typedef unsigned long long __u64; +#else +typedef __signed__ long long __s64; +typedef unsigned long long __u64; +#endif + #ifndef __WORDSIZE #define __WORDSIZE (__SIZEOF_LONG__ * 8) diff --git a/gear-lib/libbitmap/kernel.h b/gear-lib/libbitmap/kernel.h index f247ced..636ed63 100644 --- a/gear-lib/libbitmap/kernel.h +++ b/gear-lib/libbitmap/kernel.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __TOOLS_LINUX_KERNEL_H -#define __TOOLS_LINUX_KERNEL_H +#ifndef _LINUX_KERNEL_H +#define _LINUX_KERNEL_H + #include #include @@ -9,9 +10,24 @@ #include #include + +#define USHRT_MAX ((u16)(~0U)) +#define SHRT_MAX ((s16)(USHRT_MAX>>1)) +#define SHRT_MIN ((s16)(-SHRT_MAX - 1)) +#define INT_MAX ((int)(~0U>>1)) +#define INT_MIN (-INT_MAX - 1) #ifndef UINT_MAX #define UINT_MAX (~0U) #endif +#define LONG_MAX ((long)(~0UL>>1)) +#define LONG_MIN (-LONG_MAX - 1) +#define ULONG_MAX (~0UL) +#define LLONG_MAX ((long long)(~0ULL>>1)) +#define LLONG_MIN (-LLONG_MAX - 1) +#define ULLONG_MAX (~0ULL) +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) @@ -35,7 +51,9 @@ (type *)((char *)__mptr - offsetof(type, member)); }) #endif +#ifndef BUILD_BUG_ON #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) +#endif #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) #ifndef max @@ -102,7 +120,21 @@ int vscnprintf(char *buf, size_t size, const char *fmt, va_list args); int scnprintf(char * buf, size_t size, const char * fmt, ...); +#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) +#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) + +#define PAGE_SHIFT 13 +#define PAGE_SIZE (1 << PAGE_SHIFT) + +#define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) +#define ALIGN_DOWN(x, a) __ALIGN_KERNEL((x) - ((a) - 1), (a)) +#define __ALIGN_MASK(x, mask) __ALIGN_KERNEL_MASK((x), (mask)) +#define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a))) +#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) + +#ifndef ARRAY_SIZE #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) +#endif /* * This looks more complex than it should be. But we need to diff --git a/gear-lib/libbitmap/libbitmap.c b/gear-lib/libbitmap/libbitmap.c index 87ec491..5fee5d6 100644 --- a/gear-lib/libbitmap/libbitmap.c +++ b/gear-lib/libbitmap/libbitmap.c @@ -19,64 +19,141 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. ******************************************************************************/ +#define _GNU_SOURCE +#include #include "libbitmap.h" #include -//#include -int __bitmap_weight(const unsigned long *bitmap, int bits) +/** + * DOC: bitmap introduction + * + * bitmaps provide an array of bits, implemented using an an + * array of unsigned longs. The number of valid bits in a + * given bitmap does _not_ need to be an exact multiple of + * BITS_PER_LONG. + * + * The possible unused bits in the last, partially used word + * of a bitmap are 'don't care'. The implementation makes + * no particular effort to keep them zero. It ensures that + * their value will not affect the results of any operation. + * The bitmap operations that return Boolean (bitmap_empty, + * for example) or scalar (bitmap_weight, for example) results + * carefully filter out these unused bits from impacting their + * results. + * + * These operations actually hold to a slightly stronger rule: + * if you don't input any bitmaps to these ops that have some + * unused bits set, then they won't output any set unused bits + * in output bitmaps. + * + * The byte ordering of bitmaps is more natural on little + * endian architectures. See the big-endian headers + * include/asm-ppc64/bitops.h and include/asm-s390/bitops.h + * for the best explanations of this ordering. + */ + +int __bitmap_equal(const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int bits) { - int k, w = 0, lim = bits/BITS_PER_LONG; - - for (k = 0; k < lim; k++) - w += hweight_long(bitmap[k]); + unsigned int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + if (bitmap1[k] != bitmap2[k]) + return 0; if (bits % BITS_PER_LONG) - w += hweight_long(bitmap[k] & BITMAP_LAST_WORD_MASK(bits)); + if ((bitmap1[k] ^ bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) + return 0; - return w; + return 1; } -void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, - const unsigned long *bitmap2, int bits) +void __bitmap_complement(unsigned long *dst, const unsigned long *src, unsigned int bits) +{ + unsigned int k, lim = BITS_TO_LONGS(bits); + for (k = 0; k < lim; ++k) + dst[k] = ~src[k]; +} + +/** + * __bitmap_shift_right - logical right shift of the bits in a bitmap + * @dst : destination bitmap + * @src : source bitmap + * @shift : shift by this many bits + * @nbits : bitmap size, in bits + * + * Shifting right (dividing) means moving bits in the MS -> LS bit + * direction. Zeros are fed into the vacated MS positions and the + * LS bits shifted off the bottom are lost. + */ +void __bitmap_shift_right(unsigned long *dst, const unsigned long *src, + unsigned shift, unsigned nbits) +{ + unsigned k, lim = BITS_TO_LONGS(nbits); + unsigned off = shift/BITS_PER_LONG, rem = shift % BITS_PER_LONG; + unsigned long mask = BITMAP_LAST_WORD_MASK(nbits); + for (k = 0; off + k < lim; ++k) { + unsigned long upper, lower; + + /* + * If shift is not word aligned, take lower rem bits of + * word above and make them the top rem bits of result. + */ + if (!rem || off + k + 1 >= lim) + upper = 0; + else { + upper = src[off + k + 1]; + if (off + k + 1 == lim - 1) + upper &= mask; + upper <<= (BITS_PER_LONG - rem); + } + lower = src[off + k]; + if (off + k == lim - 1) + lower &= mask; + lower >>= rem; + dst[k] = lower | upper; + } + if (off) + memset(&dst[lim - off], 0, off*sizeof(unsigned long)); +} + +/** + * __bitmap_shift_left - logical left shift of the bits in a bitmap + * @dst : destination bitmap + * @src : source bitmap + * @shift : shift by this many bits + * @nbits : bitmap size, in bits + * + * Shifting left (multiplying) means moving bits in the LS -> MS + * direction. Zeros are fed into the vacated LS bit positions + * and those MS bits shifted off the top are lost. + */ + +void __bitmap_shift_left(unsigned long *dst, const unsigned long *src, + unsigned int shift, unsigned int nbits) { int k; - int nr = BITS_TO_LONGS(bits); + unsigned int lim = BITS_TO_LONGS(nbits); + unsigned int off = shift/BITS_PER_LONG, rem = shift % BITS_PER_LONG; + for (k = lim - off - 1; k >= 0; --k) { + unsigned long upper, lower; - for (k = 0; k < nr; k++) - dst[k] = bitmap1[k] | bitmap2[k]; -} - -size_t bitmap_scnprintf(unsigned long *bitmap, int nbits, - char *buf, size_t size) -{ - /* current bit is 'cur', most recently seen range is [rbot, rtop] */ - int cur, rbot, rtop; - bool first = true; - size_t ret = 0; - - rbot = cur = find_first_bit(bitmap, nbits); - while (cur < nbits) { - rtop = cur; - cur = find_next_bit(bitmap, nbits, cur + 1); - if (cur < nbits && cur <= rtop + 1) - continue; - - if (!first) - ret += scnprintf(buf + ret, size - ret, ","); - - first = false; - - ret += scnprintf(buf + ret, size - ret, "%d", rbot); - if (rbot < rtop) - ret += scnprintf(buf + ret, size - ret, "-%d", rtop); - - rbot = cur; + /* + * If shift is not word aligned, take upper rem bits of + * word below and make them the bottom rem bits of result. + */ + if (rem && k > 0) + lower = src[k - 1] >> (BITS_PER_LONG - rem); + else + lower = 0; + upper = src[k] << rem; + dst[k + off] = lower | upper; } - return ret; + if (off) + memset(dst, 0, off*sizeof(unsigned long)); } int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int bits) + const unsigned long *bitmap2, unsigned int bits) { unsigned int k; unsigned int lim = bits/BITS_PER_LONG; @@ -89,3 +166,1003 @@ int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1, BITMAP_LAST_WORD_MASK(bits)); return result != 0; } + +void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int bits) +{ + unsigned int k; + unsigned int nr = BITS_TO_LONGS(bits); + + for (k = 0; k < nr; k++) + dst[k] = bitmap1[k] | bitmap2[k]; +} + +void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int bits) +{ + unsigned int k; + unsigned int nr = BITS_TO_LONGS(bits); + + for (k = 0; k < nr; k++) + dst[k] = bitmap1[k] ^ bitmap2[k]; +} + +int __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int bits) +{ + unsigned int k; + unsigned int lim = bits/BITS_PER_LONG; + unsigned long result = 0; + + for (k = 0; k < lim; k++) + result |= (dst[k] = bitmap1[k] & ~bitmap2[k]); + if (bits % BITS_PER_LONG) + result |= (dst[k] = bitmap1[k] & ~bitmap2[k] & + BITMAP_LAST_WORD_MASK(bits)); + return result != 0; +} + +int __bitmap_intersects(const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int bits) +{ + unsigned int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + if (bitmap1[k] & bitmap2[k]) + return 1; + + if (bits % BITS_PER_LONG) + if ((bitmap1[k] & bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) + return 1; + return 0; +} + +int __bitmap_subset(const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int bits) +{ + unsigned int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + if (bitmap1[k] & ~bitmap2[k]) + return 0; + + if (bits % BITS_PER_LONG) + if ((bitmap1[k] & ~bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) + return 0; + return 1; +} + +int __bitmap_weight(const unsigned long *bitmap, unsigned int bits) +{ + unsigned int k, lim = bits/BITS_PER_LONG; + int w = 0; + + for (k = 0; k < lim; k++) + w += hweight_long(bitmap[k]); + + if (bits % BITS_PER_LONG) + w += hweight_long(bitmap[k] & BITMAP_LAST_WORD_MASK(bits)); + + return w; +} + +void __bitmap_set(unsigned long *map, unsigned int start, int len) +{ + unsigned long *p = map + BIT_WORD(start); + const unsigned int size = start + len; + int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG); + unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start); + + while (len - bits_to_set >= 0) { + *p |= mask_to_set; + len -= bits_to_set; + bits_to_set = BITS_PER_LONG; + mask_to_set = ~0UL; + p++; + } + if (len) { + mask_to_set &= BITMAP_LAST_WORD_MASK(size); + *p |= mask_to_set; + } +} + +void __bitmap_clear(unsigned long *map, unsigned int start, int len) +{ + unsigned long *p = map + BIT_WORD(start); + const unsigned int size = start + len; + int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG); + unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start); + + while (len - bits_to_clear >= 0) { + *p &= ~mask_to_clear; + len -= bits_to_clear; + bits_to_clear = BITS_PER_LONG; + mask_to_clear = ~0UL; + p++; + } + if (len) { + mask_to_clear &= BITMAP_LAST_WORD_MASK(size); + *p &= ~mask_to_clear; + } +} + +/** + * bitmap_find_next_zero_area_off - find a contiguous aligned zero area + * @map: The address to base the search on + * @size: The bitmap size in bits + * @start: The bitnumber to start searching at + * @nr: The number of zeroed bits we're looking for + * @align_mask: Alignment mask for zero area + * @align_offset: Alignment offset for zero area. + * + * The @align_mask should be one less than a power of 2; the effect is that + * the bit offset of all zero areas this function finds plus @align_offset + * is multiple of that power of 2. + */ +unsigned long bitmap_find_next_zero_area_off(unsigned long *map, + unsigned long size, + unsigned long start, + unsigned int nr, + unsigned long align_mask, + unsigned long align_offset) +{ + unsigned long index, end, i; +again: + index = find_next_zero_bit(map, size, start); + + /* Align allocation */ + index = __ALIGN_MASK(index + align_offset, align_mask) - align_offset; + + end = index + nr; + if (end > size) + return end; + i = find_next_bit(map, end, index); + if (i < end) { + start = i + 1; + goto again; + } + return index; +} + +static int hex_to_bin(char ch) +{ + if ((ch >= '0') && (ch <= '9')) + return ch - '0'; + ch = tolower(ch); + if ((ch >= 'a') && (ch <= 'f')) + return ch - 'a' + 10; + return -1; +} + + +/* + * Bitmap printing & parsing functions: first version by Nadia Yvette Chambers, + * second version by Paul Jackson, third by Joe Korty. + */ + +#define CHUNKSZ 32 +#define nbits_to_hold_value(val) fls(val) +#define BASEDEC 10 /* fancier cpuset lists input in decimal */ + +/** + * __bitmap_parse - convert an ASCII hex string into a bitmap. + * @buf: pointer to buffer containing string. + * @buflen: buffer size in bytes. If string is smaller than this + * then it must be terminated with a \0. + * @maskp: pointer to bitmap array that will contain result. + * @nmaskbits: size of bitmap, in bits. + * + * Commas group hex digits into chunks. Each chunk defines exactly 32 + * bits of the resultant bitmask. No chunk may specify a value larger + * than 32 bits (%-EOVERFLOW), and if a chunk specifies a smaller value + * then leading 0-bits are prepended. %-EINVAL is returned for illegal + * characters and for grouping errors such as "1,,5", ",44", "," and "". + * Leading and trailing whitespace accepted, but not embedded whitespace. + */ +int __bitmap_parse(const char *buf, unsigned int buflen, + unsigned long *maskp, + int nmaskbits) +{ + int c, old_c, totaldigits, ndigits, nchunks, nbits; + uint32_t chunk; + + bitmap_zero(maskp, nmaskbits); + + nchunks = nbits = totaldigits = c = 0; + do { + chunk = 0; + ndigits = totaldigits; + + /* Get the next chunk of the bitmap */ + while (buflen) { + old_c = c; + c = *buf++; + buflen--; + if (isspace(c)) + continue; + + /* + * If the last character was a space and the current + * character isn't '\0', we've got embedded whitespace. + * This is a no-no, so throw an error. + */ + if (totaldigits && c && isspace(old_c)) + return -1; + + /* A '\0' or a ',' signal the end of the chunk */ + if (c == '\0' || c == ',') + break; + + if (!isxdigit(c)) + return -1; + + /* + * Make sure there are at least 4 free bits in 'chunk'. + * If not, this hexdigit will overflow 'chunk', so + * throw an error. + */ + if (chunk & ~((1UL << (CHUNKSZ - 4)) - 1)) + return -1; + + chunk = (chunk << 4) | hex_to_bin(c); + totaldigits++; + } + if (ndigits == totaldigits) + return -1; + if (nchunks == 0 && chunk == 0) + continue; + + __bitmap_shift_left(maskp, maskp, CHUNKSZ, nmaskbits); + *maskp |= chunk; + nchunks++; + nbits += (nchunks == 1) ? nbits_to_hold_value(chunk) : CHUNKSZ; + if (nbits > nmaskbits) + return -1; + } while (buflen && c == ','); + + return 0; +} + +/** + * bitmap_parse_user - convert an ASCII hex string in a user buffer into a bitmap + * + * @ubuf: pointer to user buffer containing string. + * @ulen: buffer size in bytes. If string is smaller than this + * then it must be terminated with a \0. + * @maskp: pointer to bitmap array that will contain result. + * @nmaskbits: size of bitmap, in bits. + * + * Wrapper for __bitmap_parse(), providing it with user buffer. + * + * We cannot have this as an inline function in bitmap.h because it needs + * linux/uaccess.h to get the access_ok() declaration and this causes + * cyclic dependencies. + */ +#if 0 +int bitmap_parse_user(const char __user *ubuf, + unsigned int ulen, unsigned long *maskp, + int nmaskbits) +{ + if (!access_ok(VERIFY_READ, ubuf, ulen)) + return -EFAULT; + return __bitmap_parse((const char __force *)ubuf, + ulen, 1, maskp, nmaskbits); + +} +#endif + +/** + * bitmap_print_to_pagebuf - convert bitmap to list or hex format ASCII string + * @list: indicates whether the bitmap must be list + * @buf: page aligned buffer into which string is placed + * @maskp: pointer to bitmap to convert + * @nmaskbits: size of bitmap, in bits + * + * Output format is a comma-separated list of decimal numbers and + * ranges if list is specified or hex digits grouped into comma-separated + * sets of 8 digits/set. Returns the number of characters written to buf. + * + * It is assumed that @buf is a pointer into a PAGE_SIZE area and that + * sufficient storage remains at @buf to accommodate the + * bitmap_print_to_pagebuf() output. + */ +int bitmap_print_to_pagebuf(bool list, char *buf, const unsigned long *maskp, + int nmaskbits) +{ + ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf; + int n = 0; + + if (len > 1) + n = list ? scnprintf(buf, len, "%*pbl\n", nmaskbits, maskp) : + scnprintf(buf, len, "%*pb\n", nmaskbits, maskp); + return n; +} + +/** + * __bitmap_parselist - convert list format ASCII string to bitmap + * @buf: read nul-terminated user string from this buffer + * @buflen: buffer size in bytes. If string is smaller than this + * then it must be terminated with a \0. + * @maskp: write resulting mask here + * @nmaskbits: number of bits in mask to be written + * + * Input format is a comma-separated list of decimal numbers and + * ranges. Consecutively set bits are shown as two hyphen-separated + * decimal numbers, the smallest and largest bit numbers set in + * the range. + * Optionally each range can be postfixed to denote that only parts of it + * should be set. The range will divided to groups of specific size. + * From each group will be used only defined amount of bits. + * Syntax: range:used_size/group_size + * Example: 0-1023:2/256 ==> 0,1,256,257,512,513,768,769 + * + * Returns: 0 on success, -errno on invalid input strings. Error values: + * + * - ``-EINVAL``: second number in range smaller than first + * - ``-EINVAL``: invalid character in string + * - ``-ERANGE``: bit number specified too large for mask + */ +static int __bitmap_parselist(const char *buf, unsigned int buflen, + unsigned long *maskp, + int nmaskbits) +{ + unsigned int a, b, old_a, old_b; + unsigned int group_size, used_size, off; + int c, old_c, totaldigits, ndigits; + int at_start, in_range, in_partial_range; + + totaldigits = c = 0; + old_a = old_b = 0; + group_size = used_size = 0; + bitmap_zero(maskp, nmaskbits); + do { + at_start = 1; + in_range = 0; + in_partial_range = 0; + a = b = 0; + ndigits = totaldigits; + + /* Get the next cpu# or a range of cpu#'s */ + while (buflen) { + old_c = c; + c = *buf++; + buflen--; + if (isspace(c)) + continue; + + /* A '\0' or a ',' signal the end of a cpu# or range */ + if (c == '\0' || c == ',') + break; + /* + * whitespaces between digits are not allowed, + * but it's ok if whitespaces are on head or tail. + * when old_c is whilespace, + * if totaldigits == ndigits, whitespace is on head. + * if whitespace is on tail, it should not run here. + * as c was ',' or '\0', + * the last code line has broken the current loop. + */ + if ((totaldigits != ndigits) && isspace(old_c)) + return -1; + + if (c == '/') { + used_size = a; + at_start = 1; + in_range = 0; + a = b = 0; + continue; + } + + if (c == ':') { + old_a = a; + old_b = b; + at_start = 1; + in_range = 0; + in_partial_range = 1; + a = b = 0; + continue; + } + + if (c == '-') { + if (at_start || in_range) + return -1; + b = 0; + in_range = 1; + at_start = 1; + continue; + } + + if (!isdigit(c)) + return -1; + + b = b * 10 + (c - '0'); + if (!in_range) + a = b; + at_start = 0; + totaldigits++; + } + if (ndigits == totaldigits) + continue; + if (in_partial_range) { + group_size = a; + a = old_a; + b = old_b; + old_a = old_b = 0; + } else { + used_size = group_size = b - a + 1; + } + /* if no digit is after '-', it's wrong*/ + if (at_start && in_range) + return -1; + if (!(a <= b) || group_size == 0 || !(used_size <= group_size)) + return -1; + if (b >= nmaskbits) + return -1; + while (a <= b) { + off = min(b - a + 1, used_size); + bitmap_set(maskp, a, off); + a += group_size; + } + } while (buflen && c == ','); + return 0; +} + +int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits) +{ + char *nl = strchrnul(bp, '\n'); + int len = nl - bp; + + return __bitmap_parselist(bp, len, maskp, nmaskbits); +} + + +/** + * bitmap_parselist_user() + * + * @ubuf: pointer to user buffer containing string. + * @ulen: buffer size in bytes. If string is smaller than this + * then it must be terminated with a \0. + * @maskp: pointer to bitmap array that will contain result. + * @nmaskbits: size of bitmap, in bits. + * + * Wrapper for bitmap_parselist(), providing it with user buffer. + * + * We cannot have this as an inline function in bitmap.h because it needs + * linux/uaccess.h to get the access_ok() declaration and this causes + * cyclic dependencies. + */ +#if 0 +int bitmap_parselist_user(const char __user *ubuf, + unsigned int ulen, unsigned long *maskp, + int nmaskbits) +{ + if (!access_ok(VERIFY_READ, ubuf, ulen)) + return -EFAULT; + return __bitmap_parselist((const char *)ubuf, + ulen, maskp, nmaskbits); +} +#endif + + +/** + * bitmap_pos_to_ord - find ordinal of set bit at given position in bitmap + * @buf: pointer to a bitmap + * @pos: a bit position in @buf (0 <= @pos < @nbits) + * @nbits: number of valid bit positions in @buf + * + * Map the bit at position @pos in @buf (of length @nbits) to the + * ordinal of which set bit it is. If it is not set or if @pos + * is not a valid bit position, map to -1. + * + * If for example, just bits 4 through 7 are set in @buf, then @pos + * values 4 through 7 will get mapped to 0 through 3, respectively, + * and other @pos values will get mapped to -1. When @pos value 7 + * gets mapped to (returns) @ord value 3 in this example, that means + * that bit 7 is the 3rd (starting with 0th) set bit in @buf. + * + * The bit positions 0 through @bits are valid positions in @buf. + */ +static int bitmap_pos_to_ord(const unsigned long *buf, unsigned int pos, unsigned int nbits) +{ + if (pos >= nbits || !test_bit(pos, buf)) + return -1; + + return __bitmap_weight(buf, pos); +} + +/** + * bitmap_ord_to_pos - find position of n-th set bit in bitmap + * @buf: pointer to bitmap + * @ord: ordinal bit position (n-th set bit, n >= 0) + * @nbits: number of valid bit positions in @buf + * + * Map the ordinal offset of bit @ord in @buf to its position in @buf. + * Value of @ord should be in range 0 <= @ord < weight(buf). If @ord + * >= weight(buf), returns @nbits. + * + * If for example, just bits 4 through 7 are set in @buf, then @ord + * values 0 through 3 will get mapped to 4 through 7, respectively, + * and all other @ord values returns @nbits. When @ord value 3 + * gets mapped to (returns) @pos value 7 in this example, that means + * that the 3rd set bit (starting with 0th) is at position 7 in @buf. + * + * The bit positions 0 through @nbits-1 are valid positions in @buf. + */ +unsigned int bitmap_ord_to_pos(const unsigned long *buf, unsigned int ord, unsigned int nbits) +{ + unsigned int pos; + + for (pos = find_first_bit(buf, nbits); + pos < nbits && ord; + pos = find_next_bit(buf, nbits, pos + 1)) + ord--; + + return pos; +} + +/** + * bitmap_remap - Apply map defined by a pair of bitmaps to another bitmap + * @dst: remapped result + * @src: subset to be remapped + * @old: defines domain of map + * @new: defines range of map + * @nbits: number of bits in each of these bitmaps + * + * Let @old and @new define a mapping of bit positions, such that + * whatever position is held by the n-th set bit in @old is mapped + * to the n-th set bit in @new. In the more general case, allowing + * for the possibility that the weight 'w' of @new is less than the + * weight of @old, map the position of the n-th set bit in @old to + * the position of the m-th set bit in @new, where m == n % w. + * + * If either of the @old and @new bitmaps are empty, or if @src and + * @dst point to the same location, then this routine copies @src + * to @dst. + * + * The positions of unset bits in @old are mapped to themselves + * (the identify map). + * + * Apply the above specified mapping to @src, placing the result in + * @dst, clearing any bits previously set in @dst. + * + * For example, lets say that @old has bits 4 through 7 set, and + * @new has bits 12 through 15 set. This defines the mapping of bit + * position 4 to 12, 5 to 13, 6 to 14 and 7 to 15, and of all other + * bit positions unchanged. So if say @src comes into this routine + * with bits 1, 5 and 7 set, then @dst should leave with bits 1, + * 13 and 15 set. + */ +void bitmap_remap(unsigned long *dst, const unsigned long *src, + const unsigned long *old, const unsigned long *new, + unsigned int nbits) +{ + unsigned int oldbit, w; + + if (dst == src) /* following doesn't handle inplace remaps */ + return; + bitmap_zero(dst, nbits); + + w = bitmap_weight(new, nbits); + for_each_set_bit(oldbit, src, nbits) { + int n = bitmap_pos_to_ord(old, oldbit, nbits); + + if (n < 0 || w == 0) + set_bit(oldbit, dst); /* identity map */ + else + set_bit(bitmap_ord_to_pos(new, n % w, nbits), dst); + } +} + +/** + * bitmap_bitremap - Apply map defined by a pair of bitmaps to a single bit + * @oldbit: bit position to be mapped + * @old: defines domain of map + * @new: defines range of map + * @bits: number of bits in each of these bitmaps + * + * Let @old and @new define a mapping of bit positions, such that + * whatever position is held by the n-th set bit in @old is mapped + * to the n-th set bit in @new. In the more general case, allowing + * for the possibility that the weight 'w' of @new is less than the + * weight of @old, map the position of the n-th set bit in @old to + * the position of the m-th set bit in @new, where m == n % w. + * + * The positions of unset bits in @old are mapped to themselves + * (the identify map). + * + * Apply the above specified mapping to bit position @oldbit, returning + * the new bit position. + * + * For example, lets say that @old has bits 4 through 7 set, and + * @new has bits 12 through 15 set. This defines the mapping of bit + * position 4 to 12, 5 to 13, 6 to 14 and 7 to 15, and of all other + * bit positions unchanged. So if say @oldbit is 5, then this routine + * returns 13. + */ +int bitmap_bitremap(int oldbit, const unsigned long *old, + const unsigned long *new, int bits) +{ + int w = bitmap_weight(new, bits); + int n = bitmap_pos_to_ord(old, oldbit, bits); + if (n < 0 || w == 0) + return oldbit; + else + return bitmap_ord_to_pos(new, n % w, bits); +} + +/** + * bitmap_onto - translate one bitmap relative to another + * @dst: resulting translated bitmap + * @orig: original untranslated bitmap + * @relmap: bitmap relative to which translated + * @bits: number of bits in each of these bitmaps + * + * Set the n-th bit of @dst iff there exists some m such that the + * n-th bit of @relmap is set, the m-th bit of @orig is set, and + * the n-th bit of @relmap is also the m-th _set_ bit of @relmap. + * (If you understood the previous sentence the first time your + * read it, you're overqualified for your current job.) + * + * In other words, @orig is mapped onto (surjectively) @dst, + * using the map { | the n-th bit of @relmap is the + * m-th set bit of @relmap }. + * + * Any set bits in @orig above bit number W, where W is the + * weight of (number of set bits in) @relmap are mapped nowhere. + * In particular, if for all bits m set in @orig, m >= W, then + * @dst will end up empty. In situations where the possibility + * of such an empty result is not desired, one way to avoid it is + * to use the bitmap_fold() operator, below, to first fold the + * @orig bitmap over itself so that all its set bits x are in the + * range 0 <= x < W. The bitmap_fold() operator does this by + * setting the bit (m % W) in @dst, for each bit (m) set in @orig. + * + * Example [1] for bitmap_onto(): + * Let's say @relmap has bits 30-39 set, and @orig has bits + * 1, 3, 5, 7, 9 and 11 set. Then on return from this routine, + * @dst will have bits 31, 33, 35, 37 and 39 set. + * + * When bit 0 is set in @orig, it means turn on the bit in + * @dst corresponding to whatever is the first bit (if any) + * that is turned on in @relmap. Since bit 0 was off in the + * above example, we leave off that bit (bit 30) in @dst. + * + * When bit 1 is set in @orig (as in the above example), it + * means turn on the bit in @dst corresponding to whatever + * is the second bit that is turned on in @relmap. The second + * bit in @relmap that was turned on in the above example was + * bit 31, so we turned on bit 31 in @dst. + * + * Similarly, we turned on bits 33, 35, 37 and 39 in @dst, + * because they were the 4th, 6th, 8th and 10th set bits + * set in @relmap, and the 4th, 6th, 8th and 10th bits of + * @orig (i.e. bits 3, 5, 7 and 9) were also set. + * + * When bit 11 is set in @orig, it means turn on the bit in + * @dst corresponding to whatever is the twelfth bit that is + * turned on in @relmap. In the above example, there were + * only ten bits turned on in @relmap (30..39), so that bit + * 11 was set in @orig had no affect on @dst. + * + * Example [2] for bitmap_fold() + bitmap_onto(): + * Let's say @relmap has these ten bits set:: + * + * 40 41 42 43 45 48 53 61 74 95 + * + * (for the curious, that's 40 plus the first ten terms of the + * Fibonacci sequence.) + * + * Further lets say we use the following code, invoking + * bitmap_fold() then bitmap_onto, as suggested above to + * avoid the possibility of an empty @dst result:: + * + * unsigned long *tmp; // a temporary bitmap's bits + * + * bitmap_fold(tmp, orig, bitmap_weight(relmap, bits), bits); + * bitmap_onto(dst, tmp, relmap, bits); + * + * Then this table shows what various values of @dst would be, for + * various @orig's. I list the zero-based positions of each set bit. + * The tmp column shows the intermediate result, as computed by + * using bitmap_fold() to fold the @orig bitmap modulo ten + * (the weight of @relmap): + * + * =============== ============== ================= + * @orig tmp @dst + * 0 0 40 + * 1 1 41 + * 9 9 95 + * 10 0 40 [#f1]_ + * 1 3 5 7 1 3 5 7 41 43 48 61 + * 0 1 2 3 4 0 1 2 3 4 40 41 42 43 45 + * 0 9 18 27 0 9 8 7 40 61 74 95 + * 0 10 20 30 0 40 + * 0 11 22 33 0 1 2 3 40 41 42 43 + * 0 12 24 36 0 2 4 6 40 42 45 53 + * 78 102 211 1 2 8 41 42 74 [#f1]_ + * =============== ============== ================= + * + * .. [#f1] + * + * For these marked lines, if we hadn't first done bitmap_fold() + * into tmp, then the @dst result would have been empty. + * + * If either of @orig or @relmap is empty (no set bits), then @dst + * will be returned empty. + * + * If (as explained above) the only set bits in @orig are in positions + * m where m >= W, (where W is the weight of @relmap) then @dst will + * once again be returned empty. + * + * All bits in @dst not set by the above rule are cleared. + */ +void bitmap_onto(unsigned long *dst, const unsigned long *orig, + const unsigned long *relmap, unsigned int bits) +{ + unsigned int n, m; /* same meaning as in above comment */ + + if (dst == orig) /* following doesn't handle inplace mappings */ + return; + bitmap_zero(dst, bits); + + /* + * The following code is a more efficient, but less + * obvious, equivalent to the loop: + * for (m = 0; m < bitmap_weight(relmap, bits); m++) { + * n = bitmap_ord_to_pos(orig, m, bits); + * if (test_bit(m, orig)) + * set_bit(n, dst); + * } + */ + + m = 0; + for_each_set_bit(n, relmap, bits) { + /* m == bitmap_pos_to_ord(relmap, n, bits) */ + if (test_bit(m, orig)) + set_bit(n, dst); + m++; + } +} + +/** + * bitmap_fold - fold larger bitmap into smaller, modulo specified size + * @dst: resulting smaller bitmap + * @orig: original larger bitmap + * @sz: specified size + * @nbits: number of bits in each of these bitmaps + * + * For each bit oldbit in @orig, set bit oldbit mod @sz in @dst. + * Clear all other bits in @dst. See further the comment and + * Example [2] for bitmap_onto() for why and how to use this. + */ +void bitmap_fold(unsigned long *dst, const unsigned long *orig, + unsigned int sz, unsigned int nbits) +{ + unsigned int oldbit; + + if (dst == orig) /* following doesn't handle inplace mappings */ + return; + bitmap_zero(dst, nbits); + + for_each_set_bit(oldbit, orig, nbits) + set_bit(oldbit % sz, dst); +} + +/* + * Common code for bitmap_*_region() routines. + * bitmap: array of unsigned longs corresponding to the bitmap + * pos: the beginning of the region + * order: region size (log base 2 of number of bits) + * reg_op: operation(s) to perform on that region of bitmap + * + * Can set, verify and/or release a region of bits in a bitmap, + * depending on which combination of REG_OP_* flag bits is set. + * + * A region of a bitmap is a sequence of bits in the bitmap, of + * some size '1 << order' (a power of two), aligned to that same + * '1 << order' power of two. + * + * Returns 1 if REG_OP_ISFREE succeeds (region is all zero bits). + * Returns 0 in all other cases and reg_ops. + */ + +enum { + REG_OP_ISFREE, /* true if region is all zero bits */ + REG_OP_ALLOC, /* set all bits in region */ + REG_OP_RELEASE, /* clear all bits in region */ +}; + +static int __reg_op(unsigned long *bitmap, unsigned int pos, int order, int reg_op) +{ + int nbits_reg; /* number of bits in region */ + int index; /* index first long of region in bitmap */ + int offset; /* bit offset region in bitmap[index] */ + int nlongs_reg; /* num longs spanned by region in bitmap */ + int nbitsinlong; /* num bits of region in each spanned long */ + unsigned long mask; /* bitmask for one long of region */ + int i; /* scans bitmap by longs */ + int ret = 0; /* return value */ + + /* + * Either nlongs_reg == 1 (for small orders that fit in one long) + * or (offset == 0 && mask == ~0UL) (for larger multiword orders.) + */ + nbits_reg = 1 << order; + index = pos / BITS_PER_LONG; + offset = pos - (index * BITS_PER_LONG); + nlongs_reg = BITS_TO_LONGS(nbits_reg); + nbitsinlong = min(nbits_reg, BITS_PER_LONG); + + /* + * Can't do "mask = (1UL << nbitsinlong) - 1", as that + * overflows if nbitsinlong == BITS_PER_LONG. + */ + mask = (1UL << (nbitsinlong - 1)); + mask += mask - 1; + mask <<= offset; + + switch (reg_op) { + case REG_OP_ISFREE: + for (i = 0; i < nlongs_reg; i++) { + if (bitmap[index + i] & mask) + goto done; + } + ret = 1; /* all bits in region free (zero) */ + break; + + case REG_OP_ALLOC: + for (i = 0; i < nlongs_reg; i++) + bitmap[index + i] |= mask; + break; + + case REG_OP_RELEASE: + for (i = 0; i < nlongs_reg; i++) + bitmap[index + i] &= ~mask; + break; + } +done: + return ret; +} + +/** + * bitmap_find_free_region - find a contiguous aligned mem region + * @bitmap: array of unsigned longs corresponding to the bitmap + * @bits: number of bits in the bitmap + * @order: region size (log base 2 of number of bits) to find + * + * Find a region of free (zero) bits in a @bitmap of @bits bits and + * allocate them (set them to one). Only consider regions of length + * a power (@order) of two, aligned to that power of two, which + * makes the search algorithm much faster. + * + * Return the bit offset in bitmap of the allocated region, + * or -errno on failure. + */ +int bitmap_find_free_region(unsigned long *bitmap, unsigned int bits, int order) +{ + unsigned int pos, end; /* scans bitmap by regions of size order */ + + for (pos = 0 ; (end = pos + (1U << order)) <= bits; pos = end) { + if (!__reg_op(bitmap, pos, order, REG_OP_ISFREE)) + continue; + __reg_op(bitmap, pos, order, REG_OP_ALLOC); + return pos; + } + return -1; +} + +/** + * bitmap_release_region - release allocated bitmap region + * @bitmap: array of unsigned longs corresponding to the bitmap + * @pos: beginning of bit region to release + * @order: region size (log base 2 of number of bits) to release + * + * This is the complement to __bitmap_find_free_region() and releases + * the found region (by clearing it in the bitmap). + * + * No return value. + */ +void bitmap_release_region(unsigned long *bitmap, unsigned int pos, int order) +{ + __reg_op(bitmap, pos, order, REG_OP_RELEASE); +} + +/** + * bitmap_allocate_region - allocate bitmap region + * @bitmap: array of unsigned longs corresponding to the bitmap + * @pos: beginning of bit region to allocate + * @order: region size (log base 2 of number of bits) to allocate + * + * Allocate (set bits in) a specified region of a bitmap. + * + * Return 0 on success, or %-EBUSY if specified region wasn't + * free (not all bits were zero). + */ +int bitmap_allocate_region(unsigned long *bitmap, unsigned int pos, int order) +{ + if (!__reg_op(bitmap, pos, order, REG_OP_ISFREE)) + return -1; + return __reg_op(bitmap, pos, order, REG_OP_ALLOC); +} + +/** + * bitmap_copy_le - copy a bitmap, putting the bits into little-endian order. + * @dst: destination buffer + * @src: bitmap to copy + * @nbits: number of bits in the bitmap + * + * Require nbits % BITS_PER_LONG == 0. + */ +#ifdef __BIG_ENDIAN +void bitmap_copy_le(unsigned long *dst, const unsigned long *src, unsigned int nbits) +{ + unsigned int i; + + for (i = 0; i < nbits/BITS_PER_LONG; i++) { + if (BITS_PER_LONG == 64) + dst[i] = cpu_to_le64(src[i]); + else + dst[i] = cpu_to_le32(src[i]); + } +} +#endif + +unsigned long *bitmap_alloc(unsigned int nbits) +{ + return calloc(BITS_TO_LONGS(nbits), sizeof(unsigned long)); +} + +unsigned long *bitmap_zalloc(unsigned int nbits) +{ + return calloc(nbits, 1); +} + +void bitmap_free(const unsigned long *bitmap) +{ + free((void *)bitmap); +} + +#if BITS_PER_LONG == 64 +/** + * bitmap_from_arr32 - copy the contents of u32 array of bits to bitmap + * @bitmap: array of unsigned longs, the destination bitmap + * @buf: array of u32 (in host byte order), the source bitmap + * @nbits: number of bits in @bitmap + */ +void bitmap_from_arr32(unsigned long *bitmap, const uint32_t *buf, unsigned int nbits) +{ + unsigned int i, halfwords; + + halfwords = DIV_ROUND_UP(nbits, 32); + for (i = 0; i < halfwords; i++) { + bitmap[i/2] = (unsigned long) buf[i]; + if (++i < halfwords) + bitmap[i/2] |= ((unsigned long) buf[i]) << 32; + } + + /* Clear tail bits in last word beyond nbits. */ + if (nbits % BITS_PER_LONG) + bitmap[(halfwords - 1) / 2] &= BITMAP_LAST_WORD_MASK(nbits); +} + +/** + * bitmap_to_arr32 - copy the contents of bitmap to a u32 array of bits + * @buf: array of u32 (in host byte order), the dest bitmap + * @bitmap: array of unsigned longs, the source bitmap + * @nbits: number of bits in @bitmap + */ +void bitmap_to_arr32(uint32_t *buf, const unsigned long *bitmap, unsigned int nbits) +{ + unsigned int i, halfwords; + + halfwords = DIV_ROUND_UP(nbits, 32); + for (i = 0; i < halfwords; i++) { + buf[i] = (uint32_t) (bitmap[i/2] & UINT_MAX); + if (++i < halfwords) + buf[i] = (uint32_t) (bitmap[i/2] >> 32); + } + + /* Clear tail bits in last element of array beyond nbits. */ + if (nbits % BITS_PER_LONG) + buf[halfwords - 1] &= (uint32_t) (UINT_MAX >> ((-nbits) & 31)); +} + +#endif diff --git a/gear-lib/libbitmap/libbitmap.h b/gear-lib/libbitmap/libbitmap.h index 0b9f8a6..3193cc1 100644 --- a/gear-lib/libbitmap/libbitmap.h +++ b/gear-lib/libbitmap/libbitmap.h @@ -22,11 +22,13 @@ #ifndef LIBBITMAP_H #define LIBBITMAP_H +#include #include "bitops.h" -#include #include -//#include - +#include +#include +#include +#include #define LIBBITMAP_VERSION "0.0.1" @@ -34,44 +36,338 @@ extern "C" { #endif +/* + * bitmaps provide bit arrays that consume one or more unsigned + * longs. The bitmap interface and available operations are listed + * here, in bitmap.h + * + * Function implementations generic to all architectures are in + * lib/bitmap.c. Functions implementations that are architecture + * specific are in various include/asm-/bitops.h headers + * and other arch/ specific files. + * + * See lib/bitmap.c for more details. + */ + +/** + * DOC: bitmap overview + * + * The available bitmap operations and their rough meaning in the + * case that the bitmap is a single unsigned long are thus: + * + * Note that nbits should be always a compile time evaluable constant. + * Otherwise many inlines will generate horrible code. + * + * :: + * + * bitmap_zero(dst, nbits) *dst = 0UL + * bitmap_fill(dst, nbits) *dst = ~0UL + * bitmap_copy(dst, src, nbits) *dst = *src + * bitmap_and(dst, src1, src2, nbits) *dst = *src1 & *src2 + * bitmap_or(dst, src1, src2, nbits) *dst = *src1 | *src2 + * bitmap_xor(dst, src1, src2, nbits) *dst = *src1 ^ *src2 + * bitmap_andnot(dst, src1, src2, nbits) *dst = *src1 & ~(*src2) + * bitmap_complement(dst, src, nbits) *dst = ~(*src) + * bitmap_equal(src1, src2, nbits) Are *src1 and *src2 equal? + * bitmap_intersects(src1, src2, nbits) Do *src1 and *src2 overlap? + * bitmap_subset(src1, src2, nbits) Is *src1 a subset of *src2? + * bitmap_empty(src, nbits) Are all bits zero in *src? + * bitmap_full(src, nbits) Are all bits set in *src? + * bitmap_weight(src, nbits) Hamming Weight: number set bits + * bitmap_set(dst, pos, nbits) Set specified bit area + * bitmap_clear(dst, pos, nbits) Clear specified bit area + * bitmap_find_next_zero_area(buf, len, pos, n, mask) Find bit free area + * bitmap_find_next_zero_area_off(buf, len, pos, n, mask) as above + * bitmap_shift_right(dst, src, n, nbits) *dst = *src >> n + * bitmap_shift_left(dst, src, n, nbits) *dst = *src << n + * bitmap_remap(dst, src, old, new, nbits) *dst = map(old, new)(src) + * bitmap_bitremap(oldbit, old, new, nbits) newbit = map(old, new)(oldbit) + * bitmap_onto(dst, orig, relmap, nbits) *dst = orig relative to relmap + * bitmap_fold(dst, orig, sz, nbits) dst bits = orig bits mod sz + * bitmap_parse(buf, buflen, dst, nbits) Parse bitmap dst from kernel buf + * bitmap_parselist(buf, dst, nbits) Parse bitmap dst from kernel buf + * bitmap_find_free_region(bitmap, bits, order) Find and allocate bit region + * bitmap_release_region(bitmap, pos, order) Free specified bit region + * bitmap_allocate_region(bitmap, pos, order) Allocate specified bit region + * bitmap_from_arr32(dst, buf, nbits) Copy nbits from u32[] buf to dst + * bitmap_to_arr32(buf, src, nbits) Copy nbits from buf to u32[] dst + * + * Note, bitmap_zero() and bitmap_fill() operate over the region of + * unsigned longs, that is, bits behind bitmap till the unsigned long + * boundary will be zeroed or filled as well. Consider to use + * bitmap_clear() or bitmap_set() to make explicit zeroing or filling + * respectively. + */ + +/** + * DOC: bitmap bitops + * + * Also the following operations in asm/bitops.h apply to bitmaps.:: + * + * set_bit(bit, addr) *addr |= bit + * clear_bit(bit, addr) *addr &= ~bit + * change_bit(bit, addr) *addr ^= bit + * test_bit(bit, addr) Is bit set in *addr? + * test_and_set_bit(bit, addr) Set bit and return old value + * test_and_clear_bit(bit, addr) Clear bit and return old value + * test_and_change_bit(bit, addr) Change bit and return old value + * find_first_zero_bit(addr, nbits) Position first zero bit in *addr + * find_first_bit(addr, nbits) Position first set bit in *addr + * find_next_zero_bit(addr, nbits, bit) + * Position next zero bit in *addr >= bit + * find_next_bit(addr, nbits, bit) Position next set bit in *addr >= bit + * find_next_and_bit(addr1, addr2, nbits, bit) + * Same as find_next_bit, but in + * (*addr1 & *addr2) + * + */ + +/** + * DOC: declare bitmap + * The DECLARE_BITMAP(name,bits) macro, in linux/types.h, can be used + * to declare an array named 'name' of just enough unsigned longs to + * contain all bit positions from 0 to 'bits' - 1. + */ + #define DECLARE_BITMAP(name,bits) \ unsigned long name[BITS_TO_LONGS(bits)] -int __bitmap_weight(const unsigned long *bitmap, int bits); -void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, - const unsigned long *bitmap2, int bits); +/* + * Allocation and deallocation of bitmap. + * Provided in lib/bitmap.c to avoid circular dependency. + */ +unsigned long *bitmap_alloc(unsigned int nbits); +unsigned long *bitmap_zalloc(unsigned int nbits); +void bitmap_free(const unsigned long *bitmap); + +/* + * lib/bitmap.c provides these functions: + */ + +int __bitmap_empty(const unsigned long *bitmap, unsigned int nbits); +int __bitmap_full(const unsigned long *bitmap, unsigned int nbits); +int __bitmap_equal(const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int nbits); +void __bitmap_complement(unsigned long *dst, const unsigned long *src, + unsigned int nbits); +void __bitmap_shift_right(unsigned long *dst, const unsigned long *src, + unsigned int shift, unsigned int nbits); +void __bitmap_shift_left(unsigned long *dst, const unsigned long *src, + unsigned int shift, unsigned int nbits); int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int bits); + const unsigned long *bitmap2, unsigned int nbits); +void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int nbits); +void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int nbits); +int __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int nbits); +int __bitmap_intersects(const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int nbits); +int __bitmap_subset(const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int nbits); +int __bitmap_weight(const unsigned long *bitmap, unsigned int nbits); +void __bitmap_set(unsigned long *map, unsigned int start, int len); +void __bitmap_clear(unsigned long *map, unsigned int start, int len); + +unsigned long bitmap_find_next_zero_area_off(unsigned long *map, + unsigned long size, + unsigned long start, + unsigned int nr, + unsigned long align_mask, + unsigned long align_offset); + +/** + * bitmap_find_next_zero_area - find a contiguous aligned zero area + * @map: The address to base the search on + * @size: The bitmap size in bits + * @start: The bitnumber to start searching at + * @nr: The number of zeroed bits we're looking for + * @align_mask: Alignment mask for zero area + * + * The @align_mask should be one less than a power of 2; the effect is that + * the bit offset of all zero areas this function finds is multiples of that + * power of 2. A @align_mask of 0 means no alignment is required. + */ +static inline unsigned long +bitmap_find_next_zero_area(unsigned long *map, + unsigned long size, + unsigned long start, + unsigned int nr, + unsigned long align_mask) +{ + return bitmap_find_next_zero_area_off(map, size, start, nr, + align_mask, 0); +} + +int __bitmap_parse(const char *buf, unsigned int buflen, + unsigned long *dst, int nbits); +int bitmap_parselist(const char *buf, unsigned long *maskp, + int nmaskbits); +void bitmap_remap(unsigned long *dst, const unsigned long *src, + const unsigned long *old, const unsigned long *new, unsigned int nbits); +int bitmap_bitremap(int oldbit, + const unsigned long *old, const unsigned long *new, int bits); +void bitmap_onto(unsigned long *dst, const unsigned long *orig, + const unsigned long *relmap, unsigned int bits); +void bitmap_fold(unsigned long *dst, const unsigned long *orig, + unsigned int sz, unsigned int nbits); +int bitmap_find_free_region(unsigned long *bitmap, unsigned int bits, int order); +void bitmap_release_region(unsigned long *bitmap, unsigned int pos, int order); +int bitmap_allocate_region(unsigned long *bitmap, unsigned int pos, int order); + +#ifdef __BIG_ENDIAN +void bitmap_copy_le(unsigned long *dst, const unsigned long *src, unsigned int nbits); +#else +#define bitmap_copy_le bitmap_copy +#endif +unsigned int bitmap_ord_to_pos(const unsigned long *bitmap, unsigned int ord, unsigned int nbits); +int bitmap_print_to_pagebuf(bool list, char *buf, + const unsigned long *maskp, int nmaskbits); #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1))) - -#define BITMAP_LAST_WORD_MASK(nbits) \ -( \ - ((nbits) % BITS_PER_LONG) ? \ - (1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL \ -) +#define BITMAP_LAST_WORD_MASK(nbits) (~0UL >> (-(nbits) & (BITS_PER_LONG - 1))) #define small_const_nbits(nbits) \ (__builtin_constant_p(nbits) && (nbits) <= BITS_PER_LONG) -static inline void bitmap_zero(unsigned long *dst, int nbits) +static inline void bitmap_zero(unsigned long *dst, unsigned int nbits) { if (small_const_nbits(nbits)) *dst = 0UL; else { - int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); + unsigned int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); memset(dst, 0, len); } } static inline void bitmap_fill(unsigned long *dst, unsigned int nbits) { - unsigned int nlongs = BITS_TO_LONGS(nbits); - if (!small_const_nbits(nbits)) { - unsigned int len = (nlongs - 1) * sizeof(unsigned long); - memset(dst, 0xff, len); + if (small_const_nbits(nbits)) + *dst = ~0UL; + else { + unsigned int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); + memset(dst, 0xff, len); } - dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits); +} + +static inline void bitmap_copy(unsigned long *dst, const unsigned long *src, + unsigned int nbits) +{ + if (small_const_nbits(nbits)) + *dst = *src; + else { + unsigned int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); + memcpy(dst, src, len); + } +} + +/* + * Copy bitmap and clear tail bits in last word. + */ +static inline void bitmap_copy_clear_tail(unsigned long *dst, + const unsigned long *src, unsigned int nbits) +{ + bitmap_copy(dst, src, nbits); + if (nbits % BITS_PER_LONG) + dst[nbits / BITS_PER_LONG] &= BITMAP_LAST_WORD_MASK(nbits); +} + +/* + * On 32-bit systems bitmaps are represented as u32 arrays internally, and + * therefore conversion is not needed when copying data from/to arrays of u32. + */ +#if BITS_PER_LONG == 64 +void bitmap_from_arr32(unsigned long *bitmap, const uint32_t *buf, + unsigned int nbits); +void bitmap_to_arr32(uint32_t *buf, const unsigned long *bitmap, + unsigned int nbits); +#else +#define bitmap_from_arr32(bitmap, buf, nbits) \ + bitmap_copy_clear_tail((unsigned long *) (bitmap), \ + (const unsigned long *) (buf), (nbits)) +#define bitmap_to_arr32(buf, bitmap, nbits) \ + bitmap_copy_clear_tail((unsigned long *) (buf), \ + (const unsigned long *) (bitmap), (nbits)) +#endif + +static inline int bitmap_and(unsigned long *dst, const unsigned long *src1, + const unsigned long *src2, unsigned int nbits) +{ + if (small_const_nbits(nbits)) + return (*dst = *src1 & *src2 & BITMAP_LAST_WORD_MASK(nbits)) != 0; + return __bitmap_and(dst, src1, src2, nbits); +} + +static inline void bitmap_or(unsigned long *dst, const unsigned long *src1, + const unsigned long *src2, unsigned int nbits) +{ + if (small_const_nbits(nbits)) + *dst = *src1 | *src2; + else + __bitmap_or(dst, src1, src2, nbits); +} + +static inline void bitmap_xor(unsigned long *dst, const unsigned long *src1, + const unsigned long *src2, unsigned int nbits) +{ + if (small_const_nbits(nbits)) + *dst = *src1 ^ *src2; + else + __bitmap_xor(dst, src1, src2, nbits); +} + +static inline int bitmap_andnot(unsigned long *dst, const unsigned long *src1, + const unsigned long *src2, unsigned int nbits) +{ + if (small_const_nbits(nbits)) + return (*dst = *src1 & ~(*src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0; + return __bitmap_andnot(dst, src1, src2, nbits); +} + +static inline void bitmap_complement(unsigned long *dst, const unsigned long *src, + unsigned int nbits) +{ + if (small_const_nbits(nbits)) + *dst = ~(*src); + else + __bitmap_complement(dst, src, nbits); +} + +#ifdef __LITTLE_ENDIAN +#define BITMAP_MEM_ALIGNMENT 8 +#else +#define BITMAP_MEM_ALIGNMENT (8 * sizeof(unsigned long)) +#endif +#define BITMAP_MEM_MASK (BITMAP_MEM_ALIGNMENT - 1) + +static inline int bitmap_equal(const unsigned long *src1, + const unsigned long *src2, unsigned int nbits) +{ + if (small_const_nbits(nbits)) + return !((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits)); + if (__builtin_constant_p(nbits & BITMAP_MEM_MASK) && + IS_ALIGNED(nbits, BITMAP_MEM_ALIGNMENT)) + return !memcmp(src1, src2, nbits / 8); + return __bitmap_equal(src1, src2, nbits); +} + +static inline int bitmap_intersects(const unsigned long *src1, + const unsigned long *src2, unsigned int nbits) +{ + if (small_const_nbits(nbits)) + return ((*src1 & *src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0; + else + return __bitmap_intersects(src1, src2, nbits); +} + +static inline int bitmap_subset(const unsigned long *src1, + const unsigned long *src2, unsigned int nbits) +{ + if (small_const_nbits(nbits)) + return ! ((*src1 & ~(*src2)) & BITMAP_LAST_WORD_MASK(nbits)); + else + return __bitmap_subset(src1, src2, nbits); } static inline int bitmap_empty(const unsigned long *src, unsigned nbits) @@ -90,88 +386,114 @@ static inline int bitmap_full(const unsigned long *src, unsigned int nbits) return find_first_zero_bit(src, nbits) == nbits; } -static inline int bitmap_weight(const unsigned long *src, int nbits) +static __always_inline int bitmap_weight(const unsigned long *src, unsigned int nbits) { if (small_const_nbits(nbits)) return hweight_long(*src & BITMAP_LAST_WORD_MASK(nbits)); return __bitmap_weight(src, nbits); } -static inline void bitmap_or(unsigned long *dst, const unsigned long *src1, - const unsigned long *src2, int nbits) +static __always_inline void bitmap_set(unsigned long *map, unsigned int start, + unsigned int nbits) { - if (small_const_nbits(nbits)) - *dst = *src1 | *src2; + if (__builtin_constant_p(nbits) && nbits == 1) + __set_bit(start, map); + else if (__builtin_constant_p(start & BITMAP_MEM_MASK) && + IS_ALIGNED(start, BITMAP_MEM_ALIGNMENT) && + __builtin_constant_p(nbits & BITMAP_MEM_MASK) && + IS_ALIGNED(nbits, BITMAP_MEM_ALIGNMENT)) + memset((char *)map + start / 8, 0xff, nbits / 8); else - __bitmap_or(dst, src1, src2, nbits); + __bitmap_set(map, start, nbits); } -/** - * test_and_set_bit - Set a bit and return its old value - * @nr: Bit to set - * @addr: Address to count from - */ -static inline int test_and_set_bit(int nr, unsigned long *addr) +static __always_inline void bitmap_clear(unsigned long *map, unsigned int start, + unsigned int nbits) { - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - unsigned long old; - - old = *p; - *p = old | mask; - - return (old & mask) != 0; + if (__builtin_constant_p(nbits) && nbits == 1) + __clear_bit(start, map); + else if (__builtin_constant_p(start & BITMAP_MEM_MASK) && + IS_ALIGNED(start, BITMAP_MEM_ALIGNMENT) && + __builtin_constant_p(nbits & BITMAP_MEM_MASK) && + IS_ALIGNED(nbits, BITMAP_MEM_ALIGNMENT)) + memset((char *)map + start / 8, 0, nbits / 8); + else + __bitmap_clear(map, start, nbits); } -/** - * test_and_clear_bit - Clear a bit and return its old value - * @nr: Bit to clear - * @addr: Address to count from - */ -static inline int test_and_clear_bit(int nr, unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - unsigned long old; - - old = *p; - *p = old & ~mask; - - return (old & mask) != 0; -} - -/** - * bitmap_alloc - Allocate bitmap - * @nbits: Number of bits - */ -static inline unsigned long *bitmap_alloc(int nbits) -{ - return calloc(1, BITS_TO_LONGS(nbits) * sizeof(unsigned long)); -} - -/* - * bitmap_scnprintf - print bitmap list into buffer - * @bitmap: bitmap - * @nbits: size of bitmap - * @buf: buffer to store output - * @size: size of @buf - */ -size_t bitmap_scnprintf(unsigned long *bitmap, int nbits, - char *buf, size_t size); - -/** - * bitmap_and - Do logical and on bitmaps - * @dst: resulting bitmap - * @src1: operand 1 - * @src2: operand 2 - * @nbits: size of bitmap - */ -static inline int bitmap_and(unsigned long *dst, const unsigned long *src1, - const unsigned long *src2, unsigned int nbits) +static inline void bitmap_shift_right(unsigned long *dst, const unsigned long *src, + unsigned int shift, int nbits) { if (small_const_nbits(nbits)) - return (*dst = *src1 & *src2 & BITMAP_LAST_WORD_MASK(nbits)) != 0; - return __bitmap_and(dst, src1, src2, nbits); + *dst = (*src & BITMAP_LAST_WORD_MASK(nbits)) >> shift; + else + __bitmap_shift_right(dst, src, shift, nbits); +} + +static inline void bitmap_shift_left(unsigned long *dst, const unsigned long *src, + unsigned int shift, unsigned int nbits) +{ + if (small_const_nbits(nbits)) + *dst = (*src << shift) & BITMAP_LAST_WORD_MASK(nbits); + else + __bitmap_shift_left(dst, src, shift, nbits); +} + +static inline int bitmap_parse(const char *buf, unsigned int buflen, + unsigned long *maskp, int nmaskbits) +{ + return __bitmap_parse(buf, buflen, maskp, nmaskbits); +} + +/** + * BITMAP_FROM_U64() - Represent u64 value in the format suitable for bitmap. + * @n: u64 value + * + * Linux bitmaps are internally arrays of unsigned longs, i.e. 32-bit + * integers in 32-bit environment, and 64-bit integers in 64-bit one. + * + * There are four combinations of endianness and length of the word in linux + * ABIs: LE64, BE64, LE32 and BE32. + * + * On 64-bit kernels 64-bit LE and BE numbers are naturally ordered in + * bitmaps and therefore don't require any special handling. + * + * On 32-bit kernels 32-bit LE ABI orders lo word of 64-bit number in memory + * prior to hi, and 32-bit BE orders hi word prior to lo. The bitmap on the + * other hand is represented as an array of 32-bit words and the position of + * bit N may therefore be calculated as: word #(N/32) and bit #(N%32) in that + * word. For example, bit #42 is located at 10th position of 2nd word. + * It matches 32-bit LE ABI, and we can simply let the compiler store 64-bit + * values in memory as it usually does. But for BE we need to swap hi and lo + * words manually. + * + * With all that, the macro BITMAP_FROM_U64() does explicit reordering of hi and + * lo parts of u64. For LE32 it does nothing, and for BE environment it swaps + * hi and lo words, as is expected by bitmap. + */ +#if __BITS_PER_LONG == 64 +#define BITMAP_FROM_U64(n) (n) +#else +#define BITMAP_FROM_U64(n) ((unsigned long) ((u64)(n) & ULONG_MAX)), \ + ((unsigned long) ((u64)(n) >> 32)) +#endif + +/** + * bitmap_from_u64 - Check and swap words within u64. + * @mask: source bitmap + * @dst: destination bitmap + * + * In 32-bit Big Endian kernel, when using ``(u32 *)(&val)[*]`` + * to read u64 mask, we will get the wrong word. + * That is ``(u32 *)(&val)[0]`` gets the upper 32 bits, + * but we expect the lower 32-bits of u64. + */ +static inline void bitmap_from_u64(unsigned long *dst, uint64_t mask) +{ + dst[0] = mask & ULONG_MAX; + + if (sizeof(mask) > sizeof(unsigned long)) + dst[1] = mask >> 32; } diff --git a/gear-lib/librtsp/CMakeLists.txt b/gear-lib/librtsp/CMakeLists.txt index 53861e6..6ff70cb 100644 --- a/gear-lib/librtsp/CMakeLists.txt +++ b/gear-lib/librtsp/CMakeLists.txt @@ -1,7 +1,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.0...3.20) PROJECT(gear-lib) -INCLUDE_DIRECTORIES(. ${POSIX_INCLUDE_DIR} ${LOG_INCLUDE_DIR} ${DICT_INCLUDE_DIR} ${THREAD_INCLUDE_DIR} ${GEVENT_INCLUDE_DIR} ${DARRAY_INCLUDE_DIR} ${SOCK_INCLUDE_DIR} ${MEDIA_IO_INCLUDE_DIR} ${FILE_INCLUDE_DIR} ${QUEUE_INCLUDE_DIR} ${UVC_INCLUDE_DIR} ${TIME_INCLUDE_DIR}) +INCLUDE_DIRECTORIES(. ${POSIX_INCLUDE_DIR} ${LOG_INCLUDE_DIR} ${DICT_INCLUDE_DIR} ${THREAD_INCLUDE_DIR} ${GEVENT_INCLUDE_DIR} ${DARRAY_INCLUDE_DIR} ${SOCK_INCLUDE_DIR} ${MEDIA_IO_INCLUDE_DIR} ${FILE_INCLUDE_DIR} ${QUEUE_INCLUDE_DIR} ${AVCAP_INCLUDE_DIR} ${TIME_INCLUDE_DIR}) AUX_SOURCE_DIRECTORY(. SOURCE_FILES) ADD_LIBRARY(rtsp ${SOURCE_FILES}) diff --git a/gear-lib/librtsp/media_source_live.c b/gear-lib/librtsp/media_source_live.c index 455060a..19d046d 100644 --- a/gear-lib/librtsp/media_source_live.c +++ b/gear-lib/librtsp/media_source_live.c @@ -19,7 +19,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. ******************************************************************************/ -#include +#include #include #include #include @@ -58,12 +58,12 @@ struct x264_ctx { struct live_source_ctx { const char name[32]; - struct uvc_config conf; - struct uvc_ctx *uvc; + struct avcap_config conf; + struct avcap_ctx *uvc; bool uvc_opened; struct x264_ctx *x264; struct iovec extradata; - struct video_frame *frm; + struct media_frame frm; struct media_packet *pkt; void *priv; }; @@ -140,7 +140,7 @@ static struct x264_ctx *x264_open(struct live_source_ctx *cc) return NULL; } x264_param_default_preset(&c->param, "ultrafast" , "zerolatency"); - c->input_format = cc->uvc->conf.format; + c->input_format = cc->uvc->conf.video.format; c->param.rc.i_vbv_max_bitrate = 2500; c->param.rc.i_vbv_buffer_size = 2500; @@ -153,10 +153,10 @@ static struct x264_ctx *x264_open(struct live_source_ctx *cc) c->param.i_log_level = X264_LOG_INFO; c->param.i_csp = pixel_format_to_x264_csp(c->input_format); - c->param.i_width = cc->uvc->conf.width; - c->param.i_height = cc->uvc->conf.height; - c->param.i_fps_num = cc->uvc->conf.fps.num; - c->param.i_fps_den = cc->uvc->conf.fps.den; + c->param.i_width = cc->uvc->conf.video.width; + c->param.i_height = cc->uvc->conf.video.height; + c->param.i_fps_num = cc->uvc->conf.video.fps.num; + c->param.i_fps_den = cc->uvc->conf.video.fps.den; x264_param_apply_profile(&c->param, NULL); @@ -178,11 +178,11 @@ static struct x264_ctx *x264_open(struct live_source_ctx *cc) } c->encoder.format = VIDEO_CODEC_H264; - c->encoder.width = cc->uvc->conf.width; - c->encoder.height = cc->uvc->conf.height; + c->encoder.width = cc->uvc->conf.video.width; + c->encoder.height = cc->uvc->conf.video.height; c->encoder.bitrate = 2500; - c->encoder.framerate.num = cc->uvc->conf.fps.num; - c->encoder.framerate.den = cc->uvc->conf.fps.den; + c->encoder.framerate.num = cc->uvc->conf.video.fps.num; + c->encoder.framerate.den = cc->uvc->conf.video.fps.den; c->encoder.timebase.num = c->param.i_fps_den; c->encoder.timebase.den = c->param.i_fps_num; logi("width=%d, height=%d, timebase=%d/%d\n", c->encoder.width, c->encoder.height, c->encoder.timebase.num, c->encoder.timebase.den); @@ -348,23 +348,19 @@ static int live_open(struct media_source *ms, const char *name) logi("uvc already opened!\n"); return 0; } - c->conf.width = 640; - c->conf.height = 480; - c->conf.fps.num = 30; - c->conf.fps.den = 1; - c->conf.format = PIXEL_FORMAT_YUY2, - c->uvc = uvc_open("/dev/video0", &c->conf); + c->conf.video.width = 640; + c->conf.video.height = 480; + c->conf.video.fps.num = 30; + c->conf.video.fps.den = 1; + c->conf.video.format = PIXEL_FORMAT_YUY2, + c->uvc = avcap_open("/dev/video0", &c->conf); if (!c->uvc) { loge("uvc open failed!\n"); return -1; } - c->frm = video_frame_create(c->uvc->conf.format, c->uvc->conf.width, c->uvc->conf.height, MEDIA_MEM_SHALLOW); - if (!c->frm) { - loge("video_frame_create failed!\n"); - return -1; - } + video_frame_init(&c->frm.video, c->uvc->conf.video.format, c->uvc->conf.video.width, c->uvc->conf.video.height, MEDIA_MEM_SHALLOW); c->pkt = media_packet_create(MEDIA_TYPE_VIDEO, MEDIA_MEM_SHALLOW, NULL, 0); - if (uvc_start_stream(c->uvc, NULL)) { + if (avcap_start_stream(c->uvc, NULL)) { loge("uvc start stream failed!\n"); return -1; } @@ -381,9 +377,9 @@ static int live_open(struct media_source *ms, const char *name) static void live_close(struct media_source *ms) { struct live_source_ctx *c = (struct live_source_ctx *)ms->opaque; - uvc_stop_stream(c->uvc); + avcap_stop_stream(c->uvc); x264_close(c->x264); - uvc_close(c->uvc); + avcap_close(c->uvc); c->uvc_opened = false; } @@ -423,13 +419,13 @@ static int live_read(struct media_source *ms, void **data, size_t *len) struct live_source_ctx *c = (struct live_source_ctx *)ms->opaque; int size; ms_pre = time_now_msec(); - size = uvc_query_frame(c->uvc, c->frm); + size = avcap_query_frame(c->uvc, &c->frm); if (size < 0) { - loge("uvc_query_frame failed!\n"); + loge("avcap_query_frame failed!\n"); } ms_post = time_now_msec(); - logd("uvc_query_frame cost %" PRIu64 "ms\n", ms_post - ms_pre); - in.iov_base = c->frm; + logd("avcap_query_frame cost %" PRIu64 "ms\n", ms_post - ms_pre); + in.iov_base = &c->frm.video; in.iov_len = size; out.iov_base = c->pkt; ms_pre = time_now_msec(); diff --git a/gear-lib/libstrex/libstrex.c b/gear-lib/libstrex/libstrex.c index 3718bfa..f2264d3 100644 --- a/gear-lib/libstrex/libstrex.c +++ b/gear-lib/libstrex/libstrex.c @@ -109,6 +109,22 @@ char *strtoupper(char *dst, char *src, size_t n) return p; } +/** + * hex_to_bin - convert a hex digit to its real value + * @ch: ascii character represents hex digit + * + * hex_to_bin() converts one hex digit to its actual value or -1 in case of bad + * input. + */ +int strhex2bin(char ch) +{ + if ((ch >= '0') && (ch <= '9')) + return ch - '0'; + ch = tolower(ch); + if ((ch >= 'a') && (ch <= 'f')) + return ch - 'a' + 10; + return -1; +} static char s_base64_enc[64] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M', diff --git a/gear-lib/libstrex/libstrex.h b/gear-lib/libstrex/libstrex.h index 93e3d0b..609a1b7 100644 --- a/gear-lib/libstrex/libstrex.h +++ b/gear-lib/libstrex/libstrex.h @@ -60,6 +60,7 @@ size_t strlncpy(char *dst, size_t len, const char *src, size_t n); char *strtoupper(char *dst, char *src, size_t n); char *strtolower(char *dst, char *src, size_t n); +int strhex2bin(char ch); GEAR_API size_t base64_encode(char* target, const void *source, size_t bytes); GEAR_API size_t base64_encode_url(char* target, const void *source, size_t bytes); diff --git a/gear-lib/libuac/Android.mk b/gear-lib/libuac/Android.mk deleted file mode 100644 index 65db519..0000000 --- a/gear-lib/libuac/Android.mk +++ /dev/null @@ -1,18 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := libuac - -ifeq ($(MODE), release) -LOCAL_CFLAGS += -O2 -endif - -LIBRARIES_DIR := $(LOCAL_PATH)/../ - -LOCAL_C_INCLUDES := $(LOCAL_PATH) - -# Add your application source files here... -LOCAL_SRC_FILES := libuac.c - -include $(BUILD_SHARED_LIBRARY) diff --git a/gear-lib/libuac/Makefile b/gear-lib/libuac/Makefile deleted file mode 100644 index 2c1a93d..0000000 --- a/gear-lib/libuac/Makefile +++ /dev/null @@ -1,106 +0,0 @@ -############################################################################### -# common -############################################################################### -#ARCH: linux/arm/android/ios/win -ARCH ?= linux -OUTPUT ?= /usr/local -BUILD_DIR := $(shell pwd)/../../build/ -ARCH_INC := $(BUILD_DIR)/$(ARCH).inc -COLOR_INC := $(BUILD_DIR)/color.inc - -include $(ARCH_INC) -include $(COLOR_INC) - -CC_V ?= $(CC) -CXX_V ?= $(CXX) -LD_V ?= $(LD) -AR_V ?= $(AR) -CP_V ?= $(CP) -RM_V ?= $(RM) - -############################################################################### -# target and object -############################################################################### -LIBNAME = libuac -VER_TAG = $(shell echo ${LIBNAME} | tr 'a-z' 'A-Z') -VER = $(shell awk '/'"${VER_TAG}_VERSION"'/{print $$3}' ${LIBNAME}.h) -TGT_LIB_H = $(LIBNAME).h -TGT_LIB_A = $(LIBNAME).a -TGT_LIB_SO = $(LIBNAME).so -TGT_LIB_SO_VER = $(TGT_LIB_SO).${VER} -TGT_UNIT_TEST = test_$(LIBNAME) - -OBJS_LIB = $(LIBNAME).o pulseaudio.o -OBJS_UNIT_TEST = test_$(LIBNAME).o - -############################################################################### -# cflags and ldflags -############################################################################### -ifeq ($(MODE), release) -CFLAGS := -O2 -Wall -Werror -fPIC -LTYPE := release -else -CFLAGS := -g -Wall -Werror -fPIC -LTYPE := debug -endif -ifeq ($(OUTPUT),/usr/local) -OUTLIBPATH :=/usr/local -else -OUTLIBPATH :=$(OUTPUT)/$(LTYPE) -endif - -CFLAGS += $($(ARCH)_CFLAGS) -CFLAGS += -I$(OUTPUT)/include/gear-lib - -SHARED := -shared - -LDFLAGS := $($(ARCH)_LDFLAGS) -LDFLAGS += -pthread -lpulse -lmedia-io - -############################################################################### -# target -############################################################################### -.PHONY : all clean - -TGT := $(TGT_LIB_A) -TGT += $(TGT_LIB_SO) -TGT += $(TGT_UNIT_TEST) - -OBJS := $(OBJS_LIB) $(OBJS_UNIT_TEST) - -all: $(TGT) - -%.o:%.c - $(CC_V) -c $(CFLAGS) $< -o $@ - -$(TGT_LIB_A): $(OBJS_LIB) - $(AR_V) rcs $@ $^ - -$(TGT_LIB_SO): $(OBJS_LIB) - $(CC_V) -o $@ $^ $(SHARED) - @mv $(TGT_LIB_SO) $(TGT_LIB_SO_VER) - @ln -sf $(TGT_LIB_SO_VER) $(TGT_LIB_SO) - -$(TGT_UNIT_TEST): $(OBJS_UNIT_TEST) $(ANDROID_MAIN_OBJ) - $(CC_V) -o $@ $^ $(TGT_LIB_A) $(LDFLAGS) -L$(OUTLIBPATH)/lib/gear-lib -lfile -lposix -llog - -clean: - $(RM_V) -f $(OBJS) - $(RM_V) -f $(TGT) - $(RM_V) -f version.h - $(RM_V) -f $(TGT_LIB_SO)* - $(RM_V) -f $(TGT_LIB_SO_VER) - -install: - $(MAKEDIR_OUTPUT) - @if [ "$(MODE)" = "release" ];then $(STRIP) $(TGT); fi - $(CP_V) -r $(TGT_LIB_H) $(OUTPUT)/include/gear-lib - $(CP_V) -r $(TGT_LIB_A) $(OUTLIBPATH)/lib/gear-lib - $(CP_V) -r $(TGT_LIB_SO) $(OUTLIBPATH)/lib/gear-lib - $(CP_V) -r $(TGT_LIB_SO_VER) $(OUTLIBPATH)/lib/gear-lib - -uninstall: - cd $(OUTPUT)/include/gear-lib/ && rm -f $(TGT_LIB_H) - $(RM_V) -f $(OUTLIBPATH)/lib/gear-lib/$(TGT_LIB_A) - $(RM_V) -f $(OUTLIBPATH)/lib/gear-lib/$(TGT_LIB_SO) - $(RM_V) -f $(OUTLIBPATH)/lib/gear-lib/$(TGT_LIB_SO_VER) diff --git a/gear-lib/libuac/Makefile.nmake b/gear-lib/libuac/Makefile.nmake deleted file mode 100644 index cbf8c88..0000000 --- a/gear-lib/libuac/Makefile.nmake +++ /dev/null @@ -1,54 +0,0 @@ -############################################################################### -# common -############################################################################### -#ARCH: linux/pi/android/ios/win -LD = link -AR = lib -RM = del -############################################################################### -# target and object -############################################################################### -LIBNAME = libuac -TGT_LIB_A = $(LIBNAME).lib -TGT_LIB_SO = $(LIBNAME).dll -TGT_UNIT_TEST = test_$(LIBNAME).exe - -OBJS_LIB = $(LIBNAME).obj -OBJS_UNIT_TEST = test_$(LIBNAME).obj - -############################################################################### -# cflags and ldflags -############################################################################### -CFLAGS = /Iinclude /I. -!IF "$(MODE)"=="release" -CFLAGS = $(CFLAGS) /O2 /GF -!ELSE -CFLAGS = $(CFLAGS) /Od /W3 /Zi -!ENDIF - -LDFLAGS = /NOLOGO - -LIBS = ws2_32.lib - -############################################################################### -# target -############################################################################### -TGT = $(TGT_LIB_A) $(TGT_LIB_SO) $(TGT_UNIT_TEST) - -OBJS = $(OBJS_LIB) $(OBJS_UNIT_TEST) - -all: $(TGT) - -$(TGT_LIB_A): $(OBJS_LIB) - $(AR) $(OBJS_LIB) $(LIBS) /o:$(TGT_LIB_A) - -$(TGT_LIB_SO): $(OBJS_LIB) - $(LD) $(LDFLAGS) /Dll $(OBJS_LIB) $(LIBS) /o:$(TGT_LIB_SO) - -$(TGT_UNIT_TEST): $(OBJS_UNIT_TEST) - $(CC) $(TGT_LIB_A) $(OBJS_UNIT_TEST) /o $(TGT_UNIT_TEST) - -clean: - $(RM) $(OBJS) - $(RM) $(TGT) - $(RM) $(TGT_LIB_SO)* diff --git a/gear-lib/libuac/README.md b/gear-lib/libuac/README.md deleted file mode 100644 index 1e2cf12..0000000 --- a/gear-lib/libuac/README.md +++ /dev/null @@ -1,5 +0,0 @@ -## libuac -This is a simple libuac library. - -ffplay -ar 48000 -channels 2 -f s16le -i uac.pcm -ffplay -formats | grep PCM diff --git a/gear-lib/libuac/libuac.c b/gear-lib/libuac/libuac.c deleted file mode 100644 index 4dc5b61..0000000 --- a/gear-lib/libuac/libuac.c +++ /dev/null @@ -1,102 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2014-2020 Zhifeng Gong - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - ******************************************************************************/ -#include "libuac.h" -#include -#include - -#if defined (OS_LINUX) -extern struct uac_ops pa_ops; -#elif defined (OS_WINDOWS) -#endif - -static struct uac_ops *uac_ops[] = { -#if defined (OS_LINUX) - &pa_ops, -#elif defined (OS_WINDOWS) -#endif - NULL -}; - -struct uac_ctx *uac_open(const char *dev, struct uac_config *conf) -{ - struct uac_ctx *uac; - if (!dev || !conf) { - printf("invalid paraments!\n"); - return NULL; - } - uac = (struct uac_ctx *)calloc(1, sizeof(struct uac_ctx)); - if (!uac) { - printf("malloc failed!\n"); - return NULL; - } - uac->ops = uac_ops[0]; - uac->opaque = uac->ops->open(uac, dev, conf); - if (!uac->opaque) { - printf("open %s failed!\n", dev); - goto failed; - } - return uac; -failed: - free(uac); - return NULL; -} - - -void uac_close(struct uac_ctx *uac) -{ - if (!uac) { - printf("invalid paraments!\n"); - return; - } - uac->ops->close(uac); - free(uac); -} - -int uac_query_frame(struct uac_ctx *uac, struct audio_frame *frame) -{ - if (!uac || !frame) { - printf("invalid paraments!\n"); - return -1; - } - return uac->ops->query_frame(uac, frame); -} - -int uac_start_stream(struct uac_ctx *uac, audio_frame_cb *cb) -{ - if (!uac) { - printf("invalid paraments!\n"); - return -1; - } - uac->on_audio_frame = cb; - return uac->ops->start_stream(uac); -} - -int uac_stop_stream(struct uac_ctx *uac) -{ - if (!uac) { - printf("invalid paraments!\n"); - return -1; - } - return uac->ops->stop_stream(uac); -} - - diff --git a/gear-lib/libuac/libuac.h b/gear-lib/libuac/libuac.h deleted file mode 100644 index f446efe..0000000 --- a/gear-lib/libuac/libuac.h +++ /dev/null @@ -1,85 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2014-2020 Zhifeng Gong - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - ******************************************************************************/ -#ifndef LIBUAC_H -#define LIBUAC_H - -#include -#include -#include -#include - -#define LIBUAC_VERSION "0.1.0" - -#ifdef __cplusplus -extern "C" { -#endif - -struct uac_ctx; -struct uac_ops; -typedef int (audio_frame_cb)(struct uac_ctx *c, struct audio_frame *frame); - -struct uac_config { - enum sample_format format; - uint32_t sample_rate; - uint8_t channels; - const char *device; -}; - -struct uac_ctx { - int fd; - struct uac_config conf; - struct uac_ops *ops; - audio_frame_cb *on_audio_frame; - void *opaque; -}; - -struct uac_ops { - void *(*open)(struct uac_ctx *uac, const char *dev, struct uac_config *conf); - void (*close)(struct uac_ctx *c); - int (*ioctl)(struct uac_ctx *c, unsigned long int cmd, ...); - int (*start_stream)(struct uac_ctx *c); - int (*stop_stream)(struct uac_ctx *c); - int (*query_frame)(struct uac_ctx *c, struct audio_frame *frame); -}; - -GEAR_API struct uac_ctx *uac_open(const char *dev, struct uac_config *conf); -GEAR_API int uac_ioctl(struct uac_ctx *c, unsigned long int cmd, ...); -GEAR_API void uac_close(struct uac_ctx *c); - -/* - * active query frame one by one - */ -GEAR_API int uac_query_frame(struct uac_ctx *c, struct audio_frame *frame); - -/* - * passive get frame when cb is set, otherwise need query frame one by one - */ -GEAR_API int uac_start_stream(struct uac_ctx *uac, audio_frame_cb *cb); -GEAR_API int uac_stop_stream(struct uac_ctx *uac); - - - - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gear-lib/libuac/pulseaudio.c b/gear-lib/libuac/pulseaudio.c deleted file mode 100644 index 4541221..0000000 --- a/gear-lib/libuac/pulseaudio.c +++ /dev/null @@ -1,733 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2014-2020 Zhifeng Gong - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - ******************************************************************************/ -#include "libuac.h" -#include -#include -#include -#include -#include -#include -#include -#include - -enum speaker_layout { - SPEAKERS_UNKNOWN, /**< Unknown setting, fallback is stereo. */ - SPEAKERS_MONO, /**< Channels: MONO */ - SPEAKERS_STEREO, /**< Channels: FL, FR */ - SPEAKERS_2POINT1, /**< Channels: FL, FR, LFE */ - SPEAKERS_4POINT0, /**< Channels: FL, FR, FC, RC */ - SPEAKERS_4POINT1, /**< Channels: FL, FR, FC, LFE, RC */ - SPEAKERS_5POINT1, /**< Channels: FL, FR, FC, LFE, RL, RR */ - SPEAKERS_7POINT1 = 8, /**< Channels: FL, FR, FC, LFE, RL, RR, SL, SR */ -}; - -struct pulse_ctx { - int fd; - struct uac_ctx *parent; - bool is_streaming; - char *device; - uint64_t frame_id; - pa_sample_format_t format; - uint32_t sample_rate; - uint32_t bytes_per_frame; - uint8_t channels; - uint64_t first_ts; - enum speaker_layout speakers; - - /* pulseaudio defination */ - pa_threaded_mainloop *pa_mainloop; - pa_context *pa_ctx; - pa_stream *pa_stream; - pa_context_state_t pa_state; - pa_stream_state_t pa_stream_state; - pa_sample_spec pa_sample_spec; - pa_channel_map pa_channel_map; - pa_server_info pa_server_info; -}; - -#define NSEC_PER_SEC 1000000000LL -#define NSEC_PER_MSEC 1000000L - -#define timespec2ns(tv) \ - (((uint64_t)tv.tv_sec * 1000000000UL) + ((uint64_t)tv.tv_nsec)) - -static uint64_t samples_to_ns(size_t frames, uint32_t rate) -{ - return frames * NSEC_PER_SEC / rate; -} - -static inline uint64_t get_sample_time(size_t frames, uint32_t rate) -{ - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return timespec2ns(ts) - samples_to_ns(frames, rate); -} - -static pa_proplist *pulse_properties() -{ - pa_proplist *p = pa_proplist_new(); - pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, "libuac"); - pa_proplist_sets(p, PA_PROP_APPLICATION_ICON_NAME, "libuac"); - pa_proplist_sets(p, PA_PROP_MEDIA_ROLE, "production"); - return p; -} - -static int pulse_context_ready(struct pulse_ctx *c) -{ - pa_threaded_mainloop_lock(c->pa_mainloop); - if (!PA_CONTEXT_IS_GOOD(pa_context_get_state(c->pa_ctx))) { - pa_threaded_mainloop_unlock(c->pa_mainloop); - return -1; - } - while (pa_context_get_state(c->pa_ctx) != PA_CONTEXT_READY) { - pa_threaded_mainloop_wait(c->pa_mainloop); - } - pa_threaded_mainloop_unlock(c->pa_mainloop); - return 0; -} - -static int pulse_stream_ready(struct pulse_ctx *c) -{ - pa_threaded_mainloop_lock(c->pa_mainloop); - if (!PA_STREAM_IS_GOOD(pa_stream_get_state(c->pa_stream))) { - pa_threaded_mainloop_unlock(c->pa_mainloop); - return -1; - } - while (pa_stream_get_state(c->pa_stream) != PA_STREAM_READY) { - pa_threaded_mainloop_wait(c->pa_mainloop); - } - pa_threaded_mainloop_unlock(c->pa_mainloop); - return 0; -} - -static void pulse_state_cb(pa_context *pc, void *arg) -{ - struct pulse_ctx *c = arg; - if (c->pa_ctx != pc) { - printf("%s: c->pa_ctx=%p, pc=%p\n", __func__, c->pa_ctx, pc); - return; - } - switch (pa_context_get_state(pc)) { - case PA_CONTEXT_UNCONNECTED: - break; - case PA_CONTEXT_CONNECTING: - break; - case PA_CONTEXT_AUTHORIZING: - break; - case PA_CONTEXT_SETTING_NAME: - break; - case PA_CONTEXT_READY: - break; - case PA_CONTEXT_FAILED: - break; - case PA_CONTEXT_TERMINATED: - break; - default: - printf("%s:%d xxxx\n", __func__, __LINE__); - break; - } - pa_threaded_mainloop_signal(c->pa_mainloop, 0); -} - -static void server_info_cb(pa_context *pc, const pa_server_info *info, void *arg) -{ - struct pulse_ctx *c = arg; - if (c->pa_ctx != pc) { - printf("%s: c->pa_ctx=%p, pc=%p\n", __func__, c->pa_ctx, pc); - return; - } -#if 0 - printf("========pulse audio information========\n"); - printf(" Server Version: %s\n", info->server_version); - printf(" Server Name: %s\n", info->server_name); - printf(" Default Source Name: %s\n", info->default_source_name); - printf(" Default Sink Name: %s\n", info->default_sink_name); - printf(" Host Name: %s\n", info->host_name); - printf(" User Name: %s\n", info->user_name); - printf(" Channels: %hhu\n", info->sample_spec.channels); - printf(" Rate: %u\n", info->sample_spec.rate); - printf(" Frame Size: %lu\n", pa_frame_size(&info->sample_spec)); - printf(" Sample Size: %lu\n", pa_sample_size(&info->sample_spec)); - printf(" ChannelMap Channels: %hhu\n", info->channel_map.channels); -#endif - memcpy(&c->pa_server_info, info, sizeof(pa_server_info)); - c->device = strdup(info->default_source_name); - - memcpy(&c->pa_channel_map, &info->channel_map, sizeof(pa_channel_map)); - pa_threaded_mainloop_signal(c->pa_mainloop, 0); -} - -static void source_info_list_cb(pa_context *pc, const pa_source_info *info, - int eol, void *arg) -{ - struct pulse_ctx *c = arg; - - if (c->pa_ctx != pc) { - printf("%s: c->pa_ctx=%p, pc=%p\n", __func__, c->pa_ctx, pc); - return; - } -#if 0 - if (!eol) { - printf("========pulse audio source info list========\n"); - printf(" Source Index: %u\n", info->index); - printf(" Source Name: %s\n", info->name); - printf(" Source Description: %s\n", info->description); - printf(" Source Driver: %s\n", info->driver); - } -#endif - pa_threaded_mainloop_signal(c->pa_mainloop, 0); -} - -static enum sample_format pulse_to_sample_format(pa_sample_format_t format) -{ - switch (format) { - case PA_SAMPLE_U8: - return SAMPLE_FORMAT_PCM_U8; - case PA_SAMPLE_ALAW: - return SAMPLE_FORMAT_PCM_ALAW; - case PA_SAMPLE_ULAW: - return SAMPLE_FORMAT_PCM_ULAW; - case PA_SAMPLE_S16LE: - return SAMPLE_FORMAT_PCM_S16LE; - case PA_SAMPLE_S16BE: - return SAMPLE_FORMAT_PCM_S16BE; - case PA_SAMPLE_FLOAT32LE: - return SAMPLE_FORMAT_PCM_F32LE; - case PA_SAMPLE_FLOAT32BE: - return SAMPLE_FORMAT_PCM_F32BE; - case PA_SAMPLE_S32LE: - return SAMPLE_FORMAT_PCM_S32LE; - case PA_SAMPLE_S32BE: - return SAMPLE_FORMAT_PCM_S32BE; - case PA_SAMPLE_S24LE: - return SAMPLE_FORMAT_PCM_S24LE; - case PA_SAMPLE_S24BE: - return SAMPLE_FORMAT_PCM_S24BE; - case PA_SAMPLE_S24_32LE: - return SAMPLE_FORMAT_PCM_S24_32LE; - case PA_SAMPLE_S24_32BE: - return SAMPLE_FORMAT_PCM_S24_32BE; - default: - return SAMPLE_FORMAT_NONE; - } - return SAMPLE_FORMAT_NONE; -} - -static enum speaker_layout pulse_channels_to_speakers(uint32_t channels) -{ - switch (channels) { - case 1: - return SPEAKERS_MONO; - case 2: - return SPEAKERS_STEREO; - case 3: - return SPEAKERS_2POINT1; - case 4: - return SPEAKERS_4POINT0; - case 5: - return SPEAKERS_4POINT1; - case 6: - return SPEAKERS_5POINT1; - case 8: - return SPEAKERS_7POINT1; - } - return SPEAKERS_UNKNOWN; -} - -static void source_info_cb(pa_context *pc, const pa_source_info *info, - int eol, void *arg) -{ - struct pulse_ctx *c = arg; - if (c->pa_ctx != pc) { - printf("%s: c->pa_ctx=%p, pc=%p\n", __func__, c->pa_ctx, pc); - return; - } - if (eol != 0) { - goto exit; - } - pa_sample_format_t format = info->sample_spec.format; - if (pulse_to_sample_format(format) == SAMPLE_FORMAT_NONE) { - format = PA_SAMPLE_FLOAT32LE; - printf("Sample format %s not supported, using %s instead\n", - pa_sample_format_to_string(info->sample_spec.format), - pa_sample_format_to_string(format)); - } - - uint8_t channels = info->sample_spec.channels; - enum speaker_layout speakers = pulse_channels_to_speakers(channels); - if (speakers == SPEAKERS_UNKNOWN) { - channels = 2; - printf("%c channels not supported, using %c instead", - info->sample_spec.channels, channels); - } - - c->format = format; - c->sample_rate = info->sample_spec.rate; - c->channels = channels; - c->speakers = speakers; - -exit: - pa_threaded_mainloop_signal(c->pa_mainloop, 0); -} - -static void sink_info_list_cb(pa_context *pc, const pa_sink_info *info, - int eol, void *arg) -{ - struct pulse_ctx *c = arg; - - if (c->pa_ctx != pc) { - printf("%s: c->pa_ctx=%p, pc=%p\n", __func__, c->pa_ctx, pc); - return; - } -#if 0 - if (!eol) { - printf("========pulse audio sink info list========\n"); - printf(" Sink Index: %u\n", info->index); - printf(" Sink Name: %s\n", info->name); - printf(" Sink Description: %s\n", info->description); - printf(" Sink Driver: %s\n", info->driver); - } -#endif - pa_threaded_mainloop_signal(c->pa_mainloop, 0); -} - -static int pulse_get_server_info(struct pulse_ctx *c) -{ - int ret = 0; - pa_operation *op = NULL; - pa_operation_state_t state; - - if (pulse_context_ready(c) == -1) { - printf("pulse_context not ready\n"); - return -1; - } - - pa_threaded_mainloop_lock(c->pa_mainloop); - op = pa_context_get_server_info(c->pa_ctx, server_info_cb, c); - if (!op) { - ret = -1; - goto exit; - } - while ((state = pa_operation_get_state(op)) == PA_OPERATION_RUNNING) { - if (state == PA_OPERATION_CANCELLED) { - ret = -1; - printf("%s PA_OPERATION_CANCELLED\n", __func__); - break; - } - pa_threaded_mainloop_wait(c->pa_mainloop); - } - pa_operation_unref(op); - -exit: - pa_threaded_mainloop_unlock(c->pa_mainloop); - return ret; -} - -static int pulse_get_sink_list(struct pulse_ctx *c) -{ - int ret = 0; - pa_operation *op = NULL; - pa_operation_state_t state; - - if (pulse_context_ready(c) == -1) { - printf("pulse_context not ready\n"); - return -1; - } - - pa_threaded_mainloop_lock(c->pa_mainloop); - op = pa_context_get_sink_info_list(c->pa_ctx, sink_info_list_cb, c); - if (!op) { - ret = -1; - goto exit; - } - while ((state = pa_operation_get_state(op)) == PA_OPERATION_RUNNING) { - if (state == PA_OPERATION_CANCELLED) { - ret = -1; - printf("%s PA_OPERATION_CANCELLED\n", __func__); - break; - } - pa_threaded_mainloop_wait(c->pa_mainloop); - } - pa_operation_unref(op); - -exit: - pa_threaded_mainloop_unlock(c->pa_mainloop); - return ret; -} - -static int pulse_get_source_list(struct pulse_ctx *c) -{ - int ret = 0; - pa_operation *op = NULL; - pa_operation_state_t state; - - if (pulse_context_ready(c) == -1) { - printf("pulse_context not ready\n"); - return -1; - } - - pa_threaded_mainloop_lock(c->pa_mainloop); - op = pa_context_get_source_info_list(c->pa_ctx, source_info_list_cb, c); - if (!op) { - ret = -1; - goto exit; - } - while ((state = pa_operation_get_state(op)) == PA_OPERATION_RUNNING) { - if (state == PA_OPERATION_CANCELLED) { - ret = -1; - printf("%s PA_OPERATION_CANCELLED\n", __func__); - break; - } - pa_threaded_mainloop_wait(c->pa_mainloop); - } - pa_operation_unref(op); - -exit: - pa_threaded_mainloop_unlock(c->pa_mainloop); - return ret; -} - -static int pulse_get_source_info(struct pulse_ctx *c, const char *name) -{ - int ret = 0; - pa_operation *op = NULL; - pa_operation_state_t state; - - if (pulse_context_ready(c) == -1) { - printf("pulse_context not ready\n"); - return -1; - } - - pa_threaded_mainloop_lock(c->pa_mainloop); - op = pa_context_get_source_info_by_name(c->pa_ctx, name, source_info_cb, c); - if (!op) { - ret = -1; - goto exit; - } - while ((state = pa_operation_get_state(op)) == PA_OPERATION_RUNNING) { - if (state == PA_OPERATION_CANCELLED) { - ret = -1; - printf("%s PA_OPERATION_CANCELLED\n", __func__); - break; - } - pa_threaded_mainloop_wait(c->pa_mainloop); - } - pa_operation_unref(op); - -exit: - pa_threaded_mainloop_unlock(c->pa_mainloop); - return ret; -} - -static void read_cb(pa_stream *ps, size_t bytes, void *arg) -{ - struct pulse_ctx *c = arg; - struct uac_ctx *uac = c->parent; - struct audio_frame frame; - - const void *frames; - size_t nbytes; - - if (c->pa_stream != ps) { - printf("%s: c->pa_ctx=%p, ps=%p\n", __func__, c->pa_ctx, ps); - return; - } - pa_stream_peek(ps, &frames, &nbytes); - if (!nbytes) { - goto exit; - } else if (!frames) { - printf("Got audio hole of %zu bytes", nbytes); - pa_stream_drop(ps); - goto exit; - } - - frame.sample_rate = c->sample_rate; - frame.format = pulse_to_sample_format(c->format); - frame.data[0] = (uint8_t *)frames; - frame.total_size = nbytes; - frame.frames = nbytes / c->bytes_per_frame; - frame.timestamp = get_sample_time(frame.frames, frame.sample_rate); - - if (c->frame_id == 0) { - c->first_ts = frame.timestamp; - } - frame.timestamp -= c->first_ts; - frame.frame_id = c->frame_id; - c->frame_id++; - - if (uac->on_audio_frame) { - uac->on_audio_frame(uac, &frame); - } - - pa_stream_drop(ps); -exit: - pa_threaded_mainloop_signal(c->pa_mainloop, 0); -} - -static void write_cb(pa_stream *pa_stream, size_t bytes, void *arg) -{ - printf("%s:%d xxxx\n", __func__, __LINE__); -} - -static void overflow_cb(pa_stream *pa_stream, void *arg) -{ - printf("%s:%d xxxx\n", __func__, __LINE__); -} - -static void underflow_cb(pa_stream *pa_stream, void *arg) -{ - printf("%s:%d xxxx\n", __func__, __LINE__); -} - -static void stream_latency_update_cb(pa_stream *s, void *arg) -{ - printf("%s:%d xxxx\n", __func__, __LINE__); -} - -static void stream_state_cb(pa_stream *ps, void *arg) -{ - struct pulse_ctx *c = arg; - if (c->pa_stream != ps) { - printf("%s: c->pa_ctx=%p, ps=%p\n", __func__, c->pa_ctx, ps); - return; - } - switch (pa_stream_get_state(ps)) { - case PA_STREAM_CREATING: - break; - case PA_STREAM_UNCONNECTED: - break; - case PA_STREAM_READY: - break; - case PA_STREAM_FAILED: - break; - case PA_STREAM_TERMINATED: - break; - } - pa_threaded_mainloop_signal(c->pa_mainloop, 0); -} - -static int pulse_channel_map(pa_channel_map *pm, enum speaker_layout speakers) -{ - pm->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - pm->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - pm->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; - pm->map[3] = PA_CHANNEL_POSITION_LFE; - pm->map[4] = PA_CHANNEL_POSITION_REAR_LEFT; - pm->map[5] = PA_CHANNEL_POSITION_REAR_RIGHT; - pm->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; - pm->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; - - switch (speakers) { - case SPEAKERS_MONO: - pm->channels = 1; - pm->map[0] = PA_CHANNEL_POSITION_MONO; - break; - case SPEAKERS_STEREO: - pm->channels = 2; - break; - case SPEAKERS_2POINT1: - pm->channels = 3; - pm->map[2] = PA_CHANNEL_POSITION_LFE; - break; - case SPEAKERS_4POINT0: - pm->channels = 4; - pm->map[3] = PA_CHANNEL_POSITION_REAR_CENTER; - break; - case SPEAKERS_4POINT1: - pm->channels = 5; - pm->map[4] = PA_CHANNEL_POSITION_REAR_CENTER; - break; - case SPEAKERS_5POINT1: - pm->channels = 6; - break; - case SPEAKERS_7POINT1: - pm->channels = 8; - break; - case SPEAKERS_UNKNOWN: - default: - pm->channels = 0; - break; - } - return 0; -} - -static void *uac_pa_open(struct uac_ctx *uac, const char *dev, struct uac_config *conf) -{ - struct pulse_ctx *c = calloc(1, sizeof(struct pulse_ctx)); - - c->pa_mainloop = pa_threaded_mainloop_new(); - if (!c->pa_mainloop) { - printf("pa_threaded_mainloop_new failed!\n"); - } - pa_proplist *p = pulse_properties(); - c->pa_ctx = pa_context_new_with_proplist(pa_threaded_mainloop_get_api(c->pa_mainloop), "libuac", p); - if (!c->pa_ctx) { - printf("pa_context_new failed!\n"); - } - - pa_context_set_state_callback(c->pa_ctx, pulse_state_cb, c); - pa_context_connect(c->pa_ctx, NULL, PA_CONTEXT_NOFLAGS, NULL); - pa_threaded_mainloop_start(c->pa_mainloop); - - pa_threaded_mainloop_lock(c->pa_mainloop); - while ((c->pa_state = pa_context_get_state(c->pa_ctx)) != PA_CONTEXT_READY) { - if (c->pa_state == PA_CONTEXT_FAILED || c->pa_state == PA_CONTEXT_TERMINATED) { - printf("pa_context_state is invalid!\n"); - break; - } - pa_threaded_mainloop_wait(c->pa_mainloop); - } - pa_threaded_mainloop_unlock(c->pa_mainloop); - - if (c->pa_state != PA_CONTEXT_READY) { - printf("pa_context_state is not ready!\n"); - goto failed; - } - - pulse_get_server_info(c); - pulse_get_sink_list(c); - pulse_get_source_list(c); - - uac->conf.sample_rate = c->pa_server_info.sample_spec.rate; - uac->conf.channels = c->pa_server_info.sample_spec.channels; - uac->conf.format = pulse_to_sample_format(c->pa_server_info.sample_spec.format); - uac->conf.device = c->device; - - c->parent = uac; - c->frame_id = 0; - - return c; - -failed: - pa_threaded_mainloop_stop(c->pa_mainloop); - free(c); - return NULL; -} - -static int uac_pa_start_stream(struct uac_ctx *uac) -{ - struct pulse_ctx *c = (struct pulse_ctx *)uac->opaque; - int ret; - pa_buffer_attr attr = { -1 }; - - pulse_get_source_info(c, c->device); - - c->pa_sample_spec.format = c->format; - c->pa_sample_spec.rate = c->sample_rate; - c->pa_sample_spec.channels = c->channels; - - if (!pa_sample_spec_valid(&c->pa_sample_spec)) { - printf("Sample spec is not valid\n"); - return -1; - } - - c->bytes_per_frame = pa_frame_size(&c->pa_sample_spec); - if (c->bytes_per_frame == 0) { - printf("pa_frame_size cannot be zero!\n"); - return -1; - } - - pulse_channel_map(&c->pa_channel_map, c->speakers); - - pa_proplist *p = pulse_properties(); - - c->pa_stream = pa_stream_new_with_proplist(c->pa_ctx, c->device, &c->pa_sample_spec, &c->pa_channel_map, p); - if (!c->pa_stream) { - printf("pa_stream_new failed!\n"); - } - - pa_threaded_mainloop_lock(c->pa_mainloop); - pa_stream_set_read_callback(c->pa_stream, read_cb, c); - pa_stream_set_write_callback(c->pa_stream, write_cb, c); - pa_stream_set_state_callback(c->pa_stream, stream_state_cb, c); - pa_stream_set_overflow_callback(c->pa_stream, overflow_cb, c); - pa_stream_set_underflow_callback(c->pa_stream, underflow_cb, c); - pa_stream_set_latency_update_callback(c->pa_stream, stream_latency_update_cb, c); - pa_threaded_mainloop_unlock(c->pa_mainloop); - - attr.fragsize = pa_usec_to_bytes(25000, &c->pa_sample_spec); - attr.maxlength = (uint32_t)-1; - attr.minreq = (uint32_t)-1; - attr.prebuf = (uint32_t)-1; - attr.tlength = (uint32_t)-1; - - pa_stream_flags_t flags = PA_STREAM_INTERPOLATE_TIMING - | PA_STREAM_ADJUST_LATENCY - | PA_STREAM_AUTO_TIMING_UPDATE; - - pa_threaded_mainloop_lock(c->pa_mainloop); - ret = pa_stream_connect_record(c->pa_stream, c->device, &attr, flags); - pa_threaded_mainloop_unlock(c->pa_mainloop); - if (ret < 0) { - printf("pa_stream_connect_record failed %d", pa_context_errno(c->pa_ctx)); - } - if (pulse_stream_ready(c) == -1) { - printf("pulse_context not ready\n"); - return -1; - } - return 0; -} - -static int uac_pa_stop_stream(struct uac_ctx *uac) -{ - struct pulse_ctx *c = (struct pulse_ctx *)uac->opaque; - - pa_threaded_mainloop_lock(c->pa_mainloop); - pa_stream_set_state_callback(c->pa_stream, NULL, NULL); - pa_stream_disconnect(c->pa_stream); - pa_stream_unref(c->pa_stream); - c->pa_stream = NULL; - pa_threaded_mainloop_unlock(c->pa_mainloop); - - return 0; -} - -static int uac_pa_query_frame(struct uac_ctx *uac, struct audio_frame *frame) -{ - printf("%s not support\n", __func__); - return 0; -} - -static void uac_pa_close(struct uac_ctx *uac) -{ - struct pulse_ctx *c = (struct pulse_ctx *)uac->opaque; - - pa_threaded_mainloop_lock(c->pa_mainloop); - pa_context_set_state_callback(c->pa_ctx, NULL, NULL); - pa_context_disconnect(c->pa_ctx); - pa_context_unref(c->pa_ctx); - pa_threaded_mainloop_unlock(c->pa_mainloop); - - pa_threaded_mainloop_stop(c->pa_mainloop); - pa_threaded_mainloop_free(c->pa_mainloop); - free(c->device); - free(c); -} - -struct uac_ops pa_ops = { - .open = uac_pa_open, - .close = uac_pa_close, - .ioctl = NULL, - .start_stream = uac_pa_start_stream, - .stop_stream = uac_pa_stop_stream, - .query_frame = uac_pa_query_frame, -}; diff --git a/gear-lib/libuac/test_libuac.c b/gear-lib/libuac/test_libuac.c deleted file mode 100644 index 733a795..0000000 --- a/gear-lib/libuac/test_libuac.c +++ /dev/null @@ -1,73 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2014-2020 Zhifeng Gong - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - ******************************************************************************/ -#include "libuac.h" -#include -#include -#include -#include -#define __STDC_FORMAT_MACROS -#include - -#define OUTPUT_FILE "uac.pcm" - -static struct file *fp; - -static int on_frame(struct uac_ctx *c, struct audio_frame *frm) -{ - printf("frm[%" PRIu64 "] cnt=%d size=%" PRIu64 ", ts=%" PRIu64 " ms\n", - frm->frame_id, frm->frames, frm->total_size, frm->timestamp/1000000); - file_write(fp, frm->data[0], frm->total_size); - return 0; -} - -static int foo() -{ - struct uac_config conf = { - .format = SAMPLE_FORMAT_PCM_S16LE, - .sample_rate = 44100, - .channels = 2, - }; - struct uac_ctx *uac = uac_open("xxx", &conf); - if (!uac) { - printf("uac_open failed!\n"); - return -1; - } - printf("sample_rate: %d\n", uac->conf.sample_rate); - printf(" channel: %d\n", uac->conf.channels); - printf(" format: %s\n", sample_format_to_string(uac->conf.format)); - printf(" device: %s\n", uac->conf.device); - fp = file_open(OUTPUT_FILE, F_CREATE); - uac_start_stream(uac, on_frame); - sleep(5); - uac_stop_stream(uac); - file_close(fp); - uac_close(uac); - printf("write %s fininshed!\n", OUTPUT_FILE); - - return 0; -} - -int main(int argc, char **argv) -{ - foo(); - return 0; -} diff --git a/gear-lib/libuvc/Android.mk b/gear-lib/libuvc/Android.mk deleted file mode 100644 index cfe77ef..0000000 --- a/gear-lib/libuvc/Android.mk +++ /dev/null @@ -1,18 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := libuvc - -ifeq ($(MODE), release) -LOCAL_CFLAGS += -O2 -endif - -LIBRARIES_DIR := $(LOCAL_PATH)/../ - -LOCAL_C_INCLUDES := $(LOCAL_PATH) - -# Add your application source files here... -LOCAL_SRC_FILES := libuvc.c - -include $(BUILD_SHARED_LIBRARY) diff --git a/gear-lib/libuvc/CMakeLists.txt b/gear-lib/libuvc/CMakeLists.txt deleted file mode 100644 index 167fbf6..0000000 --- a/gear-lib/libuvc/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.0...3.20) -PROJECT(gear-lib) - -INCLUDE_DIRECTORIES(. ${POSIX_INCLUDE_DIR} ${MEDIA_IO_INCLUDE_DIR} ${THREAD_INCLUDE_DIR}) - -LIST(APPEND SOURCE_FILES libuvc.c) - -IF (DEFINED OS_LINUX) -LIST(APPEND SOURCE_FILES v4l2.c) -ELSEIF (DEFINED OS_WINDOWS) -LIST(APPEND SOURCE_FILES dshow.c) -ENDIF () - -ADD_LIBRARY(uvc ${SOURCE_FILES}) diff --git a/gear-lib/libuvc/Makefile b/gear-lib/libuvc/Makefile deleted file mode 100644 index 3a18bfe..0000000 --- a/gear-lib/libuvc/Makefile +++ /dev/null @@ -1,107 +0,0 @@ -############################################################################### -# common -############################################################################### -#ARCH: linux/arm/android/ios/win -ARCH ?= linux -OUTPUT ?= /usr/local -BUILD_DIR := $(shell pwd)/../../build/ -ARCH_INC := $(BUILD_DIR)/$(ARCH).inc -COLOR_INC := $(BUILD_DIR)/color.inc - -include $(ARCH_INC) -include $(COLOR_INC) - -CC_V ?= $(CC) -CXX_V ?= $(CXX) -LD_V ?= $(LD) -AR_V ?= $(AR) -CP_V ?= $(CP) -RM_V ?= $(RM) - -############################################################################### -# target and object -############################################################################### -LIBNAME = libuvc -VER_TAG = $(shell echo ${LIBNAME} | tr 'a-z' 'A-Z') -VER = $(shell awk '/'"${VER_TAG}_VERSION"'/{print $$3}' ${LIBNAME}.h) -TGT_LIB_H = $(LIBNAME).h -TGT_LIB_A = $(LIBNAME).a -TGT_LIB_SO = $(LIBNAME).so -TGT_LIB_SO_VER = $(TGT_LIB_SO).${VER} -TGT_UNIT_TEST = test_$(LIBNAME) - -OBJS_LIB = $(LIBNAME).o v4l2.o dummy.o usbcam.o -OBJS_UNIT_TEST = test_$(LIBNAME).o - -############################################################################### -# cflags and ldflags -############################################################################### -ifeq ($(MODE), release) -CFLAGS := -O2 -Wall -Werror -fPIC -LTYPE := release -else -CFLAGS := -g -Wall -Werror -fPIC -# -DHAVE_LIBV4L2 -LTYPE := debug -endif -ifeq ($(OUTPUT),/usr/local) -OUTLIBPATH :=/usr/local -else -OUTLIBPATH :=$(OUTPUT)/$(LTYPE) -endif -CFLAGS += $($(ARCH)_CFLAGS) -CFLAGS += -I$(OUTPUT)/include/gear-lib - -SHARED := -shared - -LDFLAGS := $($(ARCH)_LDFLAGS) -LDFLAGS += -pthread -lmedia-io -lthread -lusb-1.0 -# -lv4l2 - -############################################################################### -# target -############################################################################### -.PHONY : all clean - -TGT := $(TGT_LIB_A) -TGT += $(TGT_LIB_SO) -TGT += $(TGT_UNIT_TEST) - -OBJS := $(OBJS_LIB) $(OBJS_UNIT_TEST) - -all: $(TGT) - -%.o:%.c - $(CC_V) -c $(CFLAGS) $< -o $@ - -$(TGT_LIB_A): $(OBJS_LIB) - $(AR_V) rcs $@ $^ - -$(TGT_LIB_SO): $(OBJS_LIB) - $(CC_V) -o $@ $^ $(SHARED) - @mv $(TGT_LIB_SO) $(TGT_LIB_SO_VER) - @ln -sf $(TGT_LIB_SO_VER) $(TGT_LIB_SO) - -$(TGT_UNIT_TEST): $(OBJS_UNIT_TEST) $(ANDROID_MAIN_OBJ) - $(CC_V) -o $@ $^ $(TGT_LIB_A) $(LDFLAGS) -L$(OUTLIBPATH)/lib/gear-lib -lfile -lposix -llog - -clean: - $(RM_V) -f $(OBJS) - $(RM_V) -f $(TGT) - $(RM_V) -f version.h - $(RM_V) -f $(TGT_LIB_SO)* - $(RM_V) -f $(TGT_LIB_SO_VER) - -install: - $(MAKEDIR_OUTPUT) - @if [ "$(MODE)" = "release" ];then $(STRIP) $(TGT); fi - $(CP_V) -r $(TGT_LIB_H) $(OUTPUT)/include/gear-lib - $(CP_V) -r $(TGT_LIB_A) $(OUTLIBPATH)/lib/gear-lib - $(CP_V) -r $(TGT_LIB_SO) $(OUTLIBPATH)/lib/gear-lib - $(CP_V) -r $(TGT_LIB_SO_VER) $(OUTLIBPATH)/lib/gear-lib - -uninstall: - cd $(OUTPUT)/include/gear-lib/ && rm -f $(TGT_LIB_H) - $(RM_V) -f $(OUTLIBPATH)/lib/gear-lib/$(TGT_LIB_A) - $(RM_V) -f $(OUTLIBPATH)/lib/gear-lib/$(TGT_LIB_SO) - $(RM_V) -f $(OUTLIBPATH)/lib/gear-lib/$(TGT_LIB_SO_VER) diff --git a/gear-lib/libuvc/Makefile.nmake b/gear-lib/libuvc/Makefile.nmake deleted file mode 100644 index 9569111..0000000 --- a/gear-lib/libuvc/Makefile.nmake +++ /dev/null @@ -1,54 +0,0 @@ -############################################################################### -# common -############################################################################### -#ARCH: linux/pi/android/ios/win -LD = link -AR = lib -RM = del - -############################################################################### -# target and object -############################################################################### -LIBNAME = libuvc -TGT_LIB_A = $(LIBNAME).lib -TGT_LIB_SO = $(LIBNAME).dll -TGT_UNIT_TEST = test_$(LIBNAME).exe - -OBJS_LIB = $(LIBNAME).obj dshow.obj -OBJS_UNIT_TEST = test_$(LIBNAME).obj - -############################################################################### -# cflags and ldflags -############################################################################### -CFLAGS = /I../libposix/ /I../libmedia-io/ /I../libfile/ /I. -!IF "$(MODE)"=="release" -CFLAGS = $(CFLAGS) /O2 /GF -!ELSE -CFLAGS = $(CFLAGS) /Od /W3 /Zi -!ENDIF - -LIBS = ole32.lib strmiids.lib uuid.lib oleaut32.lib shlwapi.lib \ - ../libmedia-io/libmedia-io.lib ../libfile/libfile.lib ../libposix/libposix.lib - -############################################################################### -# target -############################################################################### -TGT = $(TGT_LIB_A) $(TGT_LIB_SO) $(TGT_UNIT_TEST) - -OBJS = $(OBJS_LIB) $(OBJS_UNIT_TEST) - -all: $(TGT) - -$(TGT_LIB_A): $(OBJS_LIB) - $(AR) $(OBJS_LIB) $(LIBS) /out:$(TGT_LIB_A) - -$(TGT_LIB_SO): $(OBJS_LIB) - $(LD) /Dll $(OBJS_LIB) $(LIBS) - -$(TGT_UNIT_TEST): $(OBJS_UNIT_TEST) - $(CC) $(TGT_LIB_A) $(OBJS_UNIT_TEST) /link $(LIBS) - -clean: - $(RM) $(OBJS) - $(RM) $(TGT) - $(RM) $(TGT_LIB_SO)* diff --git a/gear-lib/libuvc/README.md b/gear-lib/libuvc/README.md deleted file mode 100644 index 7316064..0000000 --- a/gear-lib/libuvc/README.md +++ /dev/null @@ -1,99 +0,0 @@ -## libuvc -This is a simple libuvc library. -if you want to enable HAVE_LIBV4L2, please install libv4l2-dev - -* v4l2: video for linux -* dummy: file of frame sequence, as virtual device -* dshow: windows video api - -# pi -sudo modprobe bcm2835_v4l2 - -ffplay -pix_fmts -x86_usbcam: -ffplay -f rawvideo -pixel_format yuyv422 -video_size 640x480 uvc.yuv -raspberrypi: -ffplay -f rawvideo -pixel_format yuv420p -video_size 640x480 uvc.yuv - -x86 $ ./test_libuvc -[V4L2 Input information]: - input.name: "Camera 1" -[V4L2 Capability Information]: - cap.driver: "uvcvideo" - cap.card: "Lenovo EasyCamera: Lenovo EasyC" - cap.bus_info: "usb-0000:00:1d.0-1.6" - cap.version: "266002" - cap.capabilities: - VIDEO_CAPTURE - STREAMING -[V4L2 Support Format]: - 0. [YUYV] "YUYV 4:2:2" - 1. [MJPG] "Motion-JPEG" -[V4L2 Supported Control]: - Brightness, range: [-64, 64], default: 0, current: 0 - Contrast, range: [0, 64], default: 32, current: 32 - Saturation, range: [0, 128], default: 64, current: 64 - Hue, range: [-180, 180], default: 0, current: 0 - White Balance Temperature, Auto, range: [0, 1], default: 1, current: 1 - Gamma, range: [100, 500], default: 300, current: 300 - Power Line Frequency, range: [0, 2], default: 1, current: 1 - White Balance Temperature, range: [2800, 6500], default: 4650, current: 4650 - Sharpness, range: [0, 8], default: 6, current: 6 - Backlight Compensation, range: [0, 2], default: 0, current: 0 - - -raspberrypi0w $ ./test_libuvc -[V4L2 Input information]: - input.name: "Camera 0" -[V4L2 Capability Information]: - cap.driver: "bm2835 mmal" - cap.card: "mmal service 16.1" - cap.bus_info: "platform:bcm2835-v4l2" - cap.version: "265799" - cap.capabilities: - VIDEO_CAPTURE - VIDEO_OVERLAY - READWRITE - STREAMING -[V4L2 Support Format]: - 0. [YU12] "Planar YUV 4:2:0" - 1. [YUYV] "YUYV 4:2:2" - 2. [RGB3] "24-bit RGB 8-8-8" - 3. [JPEG] "JFIF JPEG" - 4. [H264] "H.264" - 5. [MJPG] "Motion-JPEG" - 6. [YVYU] "YVYU 4:2:2" - 7. [VYUY] "VYUY 4:2:2" - 8. [UYVY] "UYVY 4:2:2" - 9. [NV12] "Y/CbCr 4:2:0" - 10. [BGR3] "24-bit BGR 8-8-8" - 11. [YV12] "Planar YVU 4:2:0" - 12. [NV21] "Y/CrCb 4:2:0" - 13. [BGR4] "32-bit BGRA/X 8-8-8-8" -[V4L2 Supported Control]: - Brightness, range: [0, 100], default: 50, current: 50 - Contrast, range: [-100, 100], default: 0, current: 0 - Saturation, range: [-100, 100], default: 0, current: 0 - Power Line Frequency, range: [0, 3], default: 1, current: 1 - Sharpness, range: [-100, 100], default: 0, current: 0 - - -raspberrypi2b $ ./test_libuvc -[V4L2 Input information]: - input.name: "Camera 0" -[V4L2 Capability Information]: - cap.driver: "unicam" - cap.card: "unicam" - cap.bus_info: "platform:3f801000.csi" - cap.version: "330303" - cap.capabilities: - VIDEO_CAPTURE - READWRITE - STREAMING -[V4L2 Support Format]: - 0. [BA81] "8-bit Bayer BGBG/GRGR" - 1. [pBAA] "10-bit Bayer BGBG/GRGR Packed" - 2. [BG10] "10-bit Bayer BGBG/GRGR" -[V4L2 Supported Control]: - White Balance, Automatic, range: [0, 1], default: 0, current: 0 - diff --git a/gear-lib/libuvc/dshow.c b/gear-lib/libuvc/dshow.c deleted file mode 100644 index 0d23093..0000000 --- a/gear-lib/libuvc/dshow.c +++ /dev/null @@ -1,1177 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2014-2020 Zhifeng Gong - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - ******************************************************************************/ -#define _CRT_SECURE_NO_WARNINGS /* Disable safety warning for wcscpy() */ -#include "dshow.h" -#include "libuvc.h" -#include -#include "libuvc.h" - -struct dshow_ctx { - int fd; - char *name; - char *unique_name; - int width; - int height; - uint32_t fps_num; - uint32_t fps_den; - uint64_t first_ts; - uint64_t frame_id; - IGraphBuilder *graph; - ICaptureGraphBuilder2 *capgraph; - IMediaControl *mctrl; - IMediaEvent *mevent; - IBaseFilter *dev_filter; - IPin *device_pin; - dshow_filter *cap_filter; - ICreateDevEnum *devenum; - HANDLE mutex; - HANDLE event[2]; /* event[0] is set by DirectShow - * event[1] is set by callback() */ - struct uvc_ctx *uvc; - struct video_frame frame; -}; - - -/***************************************************************************** - * dshow_enum_pins - ****************************************************************************/ -DECLARE_QUERYINTERFACE(dshow_enum_pins, {{&IID_IUnknown,0}, {&IID_IEnumPins,0}}) -DECLARE_ADDREF(dshow_enum_pins) -DECLARE_RELEASE(dshow_enum_pins) - -long WINAPI dshow_enum_pins_Next(dshow_enum_pins *this, unsigned long n, - IPin **pins, unsigned long *fetched) -{ - int count = 0; - dshowdebug("dshow_enum_pins_Next(%p)\n", this); - if (!pins) - return E_POINTER; - if (!this->pos && n == 1) { - dshow_pin_AddRef(this->pin); - *pins = (IPin *) this->pin; - count = 1; - this->pos = 1; - } - if (fetched) - *fetched = count; - if (!count) - return S_FALSE; - return S_OK; -} - -long WINAPI dshow_enum_pins_Skip(dshow_enum_pins *this, unsigned long n) -{ - dshowdebug("dshow_enum_pins_Skip(%p)\n", this); - if (n) /* Any skip will always fall outside of the only valid pin. */ - return S_FALSE; - return S_OK; -} - -long WINAPI dshow_enum_pins_Reset(dshow_enum_pins *this) -{ - dshowdebug("dshow_enum_pins_Reset(%p)\n", this); - this->pos = 0; - return S_OK; -} - -long WINAPI dshow_enum_pins_Clone(dshow_enum_pins *this, dshow_enum_pins **pins) -{ - dshow_enum_pins *new; - dshowdebug("dshow_enum_pins_Clone(%p)\n", this); - if (!pins) - return E_POINTER; - new = dshow_enum_pins_Create(this->pin, this->filter); - if (!new) - return E_OUTOFMEMORY; - new->pos = this->pos; - *pins = new; - return S_OK; -} - -static int dshow_enum_pins_Setup(dshow_enum_pins *this, dshow_pin *pin, - dshow_filter *filter) -{ - IEnumPinsVtbl *vtbl = this->vtbl; - SETVTBL(vtbl, dshow_enum_pins, QueryInterface); - SETVTBL(vtbl, dshow_enum_pins, AddRef); - SETVTBL(vtbl, dshow_enum_pins, Release); - SETVTBL(vtbl, dshow_enum_pins, Next); - SETVTBL(vtbl, dshow_enum_pins, Skip); - SETVTBL(vtbl, dshow_enum_pins, Reset); - SETVTBL(vtbl, dshow_enum_pins, Clone); - - this->pin = pin; - this->filter = filter; - dshow_filter_AddRef(this->filter); - - return 1; -} - -static int dshow_enum_pins_Cleanup(dshow_enum_pins *this) -{ - dshow_filter_Release(this->filter); - return 1; -} - -DECLARE_CREATE(dshow_enum_pins, dshow_enum_pins_Setup(this, pin, filter), - dshow_pin *pin, dshow_filter *filter) -DECLARE_DESTROY(dshow_enum_pins, dshow_enum_pins_Cleanup) - -/***************************************************************************** - * dshow_filter - ****************************************************************************/ -DECLARE_QUERYINTERFACE(dshow_filter, {{&IID_IUnknown,0}, {&IID_IBaseFilter,0}}) -DECLARE_ADDREF(dshow_filter) -DECLARE_RELEASE(dshow_filter) - -long WINAPI dshow_filter_GetClassID(dshow_filter *this, CLSID *id) -{ - dshowdebug("dshow_filter_GetClassID(%p)\n", this); - /* I'm not creating a ClassID just for this. */ - return E_FAIL; -} - -long WINAPI dshow_filter_Stop(dshow_filter *this) -{ - dshowdebug("dshow_filter_Stop(%p)\n", this); - this->state = State_Stopped; - return S_OK; -} - -long WINAPI dshow_filter_Pause(dshow_filter *this) -{ - dshowdebug("dshow_filter_Pause(%p)\n", this); - this->state = State_Paused; - return S_OK; -} - -long WINAPI dshow_filter_Run(dshow_filter *this, REFERENCE_TIME start) -{ - dshowdebug("dshow_filter_Run(%p) %"PRId64"\n", this, start); - this->state = State_Running; - this->start_time = start; - return S_OK; -} - -long WINAPI dshow_filter_GetState(dshow_filter *this, DWORD ms, - FILTER_STATE *state) -{ - dshowdebug("dshow_filter_GetState(%p)\n", this); - if (!state) - return E_POINTER; - *state = this->state; - return S_OK; -} - -long WINAPI dshow_filter_SetSyncSource(dshow_filter *this, IReferenceClock *clock) -{ - dshowdebug("dshow_filter_SetSyncSource(%p)\n", this); - - if (this->clock != clock) { - if (this->clock) - IReferenceClock_Release(this->clock); - this->clock = clock; - if (clock) - IReferenceClock_AddRef(clock); - } - - return S_OK; -} - -long WINAPI dshow_filter_GetSyncSource(dshow_filter *this, IReferenceClock **clock) -{ - dshowdebug("dshow_filter_GetSyncSource(%p)\n", this); - - if (!clock) - return E_POINTER; - if (this->clock) - IReferenceClock_AddRef(this->clock); - *clock = this->clock; - - return S_OK; -} - -long WINAPI dshow_filter_EnumPins(dshow_filter *this, IEnumPins **enumpin) -{ - dshow_enum_pins *new; - dshowdebug("dshow_filter_EnumPins(%p)\n", this); - - if (!enumpin) - return E_POINTER; - new = dshow_enum_pins_Create(this->pin, this); - if (!new) - return E_OUTOFMEMORY; - - *enumpin = (IEnumPins *) new; - return S_OK; -} - -long WINAPI dshow_filter_FindPin(dshow_filter *this, const wchar_t *id, IPin **pin) -{ - dshow_pin *found = NULL; - dshowdebug("dshow_filter_FindPin(%p)\n", this); - - if (!id || !pin) - return E_POINTER; - if (!wcscmp(id, L"In")) { - found = this->pin; - dshow_pin_AddRef(found); - } - *pin = (IPin *) found; - if (!found) - return VFW_E_NOT_FOUND; - - return S_OK; -} - -long WINAPI dshow_filter_QueryFilterInfo(dshow_filter *this, FILTER_INFO *info) -{ - dshowdebug("dshow_filter_QueryFilterInfo(%p)\n", this); - - if (!info) - return E_POINTER; - if (this->info.pGraph) - IFilterGraph_AddRef(this->info.pGraph); - *info = this->info; - - return S_OK; -} - -long WINAPI dshow_filter_JoinFilterGraph(dshow_filter *this, IFilterGraph *graph, - const wchar_t *name) -{ - dshowdebug("dshow_filter_JoinFilterGraph(%p)\n", this); - - this->info.pGraph = graph; - if (name) - wcscpy(this->info.achName, name); - - return S_OK; -} - -long WINAPI dshow_filter_QueryVendorInfo(dshow_filter *this, wchar_t **info) -{ - dshowdebug("dshow_filter_QueryVendorInfo(%p)\n", this); - - if (!info) - return E_POINTER; - return E_NOTIMPL; /* don't have to do anything here */ -} - -static int dshow_filter_setup(dshow_filter *this, void *priv_data, - void *callback, int type) -{ - IBaseFilterVtbl *vtbl = this->vtbl; - SETVTBL(vtbl, dshow_filter, QueryInterface); - SETVTBL(vtbl, dshow_filter, AddRef); - SETVTBL(vtbl, dshow_filter, Release); - SETVTBL(vtbl, dshow_filter, GetClassID); - SETVTBL(vtbl, dshow_filter, Stop); - SETVTBL(vtbl, dshow_filter, Pause); - SETVTBL(vtbl, dshow_filter, Run); - SETVTBL(vtbl, dshow_filter, GetState); - SETVTBL(vtbl, dshow_filter, SetSyncSource); - SETVTBL(vtbl, dshow_filter, GetSyncSource); - SETVTBL(vtbl, dshow_filter, EnumPins); - SETVTBL(vtbl, dshow_filter, FindPin); - SETVTBL(vtbl, dshow_filter, QueryFilterInfo); - SETVTBL(vtbl, dshow_filter, JoinFilterGraph); - SETVTBL(vtbl, dshow_filter, QueryVendorInfo); - - this->pin = dshow_pin_Create(this); - - this->priv_data = priv_data; - this->callback = callback; - - return 1; -} - -static int dshow_filter_Cleanup(dshow_filter *this) -{ - dshow_pin_Release(this->pin); - return 1; -} - -DECLARE_CREATE(dshow_filter, dshow_filter_setup(this, priv_data, callback, type), - void *priv_data, void *callback, int type) -DECLARE_DESTROY(dshow_filter, dshow_filter_Cleanup) - - -/***************************************************************************** - * dshow_pin - ****************************************************************************/ -DECLARE_QUERYINTERFACE(dshow_pin, {{&IID_IUnknown,0}, {&IID_IPin,0}, - {&IID_IMemInputPin,imemoffset}}) -DECLARE_ADDREF(dshow_pin) -DECLARE_RELEASE(dshow_pin) - -long WINAPI dshow_pin_Connect(dshow_pin *this, IPin *pin, const AM_MEDIA_TYPE *type) -{ - dshowdebug("dshow_pin_Connect(%p, %p, %p)\n", this, pin, type); - /* Input pins receive connections. */ - return S_FALSE; -} - -long WINAPI dshow_pin_ReceiveConnection(dshow_pin *this, IPin *pin, - const AM_MEDIA_TYPE *type) -{ - dshowdebug("dshow_pin_ReceiveConnection(%p)\n", this); - - if (!pin) - return E_POINTER; - if (this->connectedto) - return VFW_E_ALREADY_CONNECTED; - - if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) - return VFW_E_TYPE_NOT_ACCEPTED; - - IPin_AddRef(pin); - this->connectedto = pin; - - return S_OK; -} - -long WINAPI dshow_pin_Disconnect(dshow_pin *this) -{ - dshowdebug("dshow_pin_Disconnect(%p)\n", this); - - if (this->filter->state != State_Stopped) - return VFW_E_NOT_STOPPED; - if (!this->connectedto) - return S_FALSE; - IPin_Release(this->connectedto); - this->connectedto = NULL; - - return S_OK; -} - -long WINAPI dshow_pin_ConnectedTo(dshow_pin *this, IPin **pin) -{ - dshowdebug("dshow_pin_ConnectedTo(%p)\n", this); - - if (!pin) - return E_POINTER; - if (!this->connectedto) - return VFW_E_NOT_CONNECTED; - IPin_AddRef(this->connectedto); - *pin = this->connectedto; - - return S_OK; -} - -long copy_dshow_media_type(AM_MEDIA_TYPE *dst, const AM_MEDIA_TYPE *src) -{ - uint8_t *pbFormat = NULL; - - if (src->cbFormat) { - pbFormat = CoTaskMemAlloc(src->cbFormat); - if (!pbFormat) - return E_OUTOFMEMORY; - memcpy(pbFormat, src->pbFormat, src->cbFormat); - } - - *dst = *src; - dst->pUnk = NULL; - dst->pbFormat = pbFormat; - - return S_OK; -} - -long WINAPI dshow_pin_ConnectionMediaType(dshow_pin *this, AM_MEDIA_TYPE *type) -{ - dshowdebug("dshow_pin_ConnectionMediaType(%p)\n", this); - - if (!type) - return E_POINTER; - if (!this->connectedto) - return VFW_E_NOT_CONNECTED; - - return copy_dshow_media_type(type, &this->type); -} - -long WINAPI dshow_pin_QueryPinInfo(dshow_pin *this, PIN_INFO *info) -{ - dshowdebug("dshow_pin_QueryPinInfo(%p)\n", this); - - if (!info) - return E_POINTER; - - if (this->filter) - dshow_filter_AddRef(this->filter); - - info->pFilter = (IBaseFilter *) this->filter; - info->dir = PINDIR_INPUT; - wcscpy(info->achName, L"Capture"); - - return S_OK; -} - -long WINAPI dshow_pin_QueryDirection(dshow_pin *this, PIN_DIRECTION *dir) -{ - dshowdebug("dshow_pin_QueryDirection(%p)\n", this); - if (!dir) - return E_POINTER; - *dir = PINDIR_INPUT; - return S_OK; -} - -long WINAPI dshow_pin_QueryId(dshow_pin *this, wchar_t **id) -{ - dshowdebug("dshow_pin_QueryId(%p)\n", this); - - if (!id) - return E_POINTER; - - *id = wcsdup(L"libAV Pin"); - - return S_OK; -} - -long WINAPI dshow_pin_QueryAccept(dshow_pin *this, const AM_MEDIA_TYPE *type) -{ - dshowdebug("dshow_pin_QueryAccept(%p)\n", this); - return S_FALSE; -} - -long WINAPI dshow_pin_EnumMediaTypes(dshow_pin *this, IEnumMediaTypes **enumtypes) -{ - const AM_MEDIA_TYPE *type = NULL; - dshow_enum_media_types *new; - dshowdebug("dshow_pin_EnumMediaTypes(%p)\n", this); - - if (!enumtypes) - return E_POINTER; - new = dshow_enum_media_types_Create(type); - if (!new) - return E_OUTOFMEMORY; - - *enumtypes = (IEnumMediaTypes *) new; - return S_OK; -} - -long WINAPI dshow_pin_QueryInternalConnections(dshow_pin *this, IPin **pin, - unsigned long *npin) -{ - dshowdebug("dshow_pin_QueryInternalConnections(%p)\n", this); - return E_NOTIMPL; -} - -long WINAPI dshow_pin_EndOfStream(dshow_pin *this) -{ - dshowdebug("dshow_pin_EndOfStream(%p)\n", this); - /* I don't care. */ - return S_OK; -} - -long WINAPI dshow_pin_BeginFlush(dshow_pin *this) -{ - dshowdebug("dshow_pin_BeginFlush(%p)\n", this); - /* I don't care. */ - return S_OK; -} - -long WINAPI dshow_pin_EndFlush(dshow_pin *this) -{ - dshowdebug("dshow_pin_EndFlush(%p)\n", this); - /* I don't care. */ - return S_OK; -} - -long WINAPI dshow_pin_NewSegment(dshow_pin *this, REFERENCE_TIME start, - REFERENCE_TIME stop, double rate) -{ - dshowdebug("dshow_pin_NewSegment(%p)\n", this); - /* I don't care. */ - return S_OK; -} - -static int dshow_pin_setup(dshow_pin *this, dshow_filter *filter) -{ - IPinVtbl *vtbl = this->vtbl; - IMemInputPinVtbl *imemvtbl; - - if (!filter) - return 0; - - imemvtbl = malloc(sizeof(IMemInputPinVtbl)); - if (!imemvtbl) - return 0; - - SETVTBL(imemvtbl, dshow_input_pin, QueryInterface); - SETVTBL(imemvtbl, dshow_input_pin, AddRef); - SETVTBL(imemvtbl, dshow_input_pin, Release); - SETVTBL(imemvtbl, dshow_input_pin, GetAllocator); - SETVTBL(imemvtbl, dshow_input_pin, NotifyAllocator); - SETVTBL(imemvtbl, dshow_input_pin, GetAllocatorRequirements); - SETVTBL(imemvtbl, dshow_input_pin, Receive); - SETVTBL(imemvtbl, dshow_input_pin, ReceiveMultiple); - SETVTBL(imemvtbl, dshow_input_pin, ReceiveCanBlock); - - this->imemvtbl = imemvtbl; - - SETVTBL(vtbl, dshow_pin, QueryInterface); - SETVTBL(vtbl, dshow_pin, AddRef); - SETVTBL(vtbl, dshow_pin, Release); - SETVTBL(vtbl, dshow_pin, Connect); - SETVTBL(vtbl, dshow_pin, ReceiveConnection); - SETVTBL(vtbl, dshow_pin, Disconnect); - SETVTBL(vtbl, dshow_pin, ConnectedTo); - SETVTBL(vtbl, dshow_pin, ConnectionMediaType); - SETVTBL(vtbl, dshow_pin, QueryPinInfo); - SETVTBL(vtbl, dshow_pin, QueryDirection); - SETVTBL(vtbl, dshow_pin, QueryId); - SETVTBL(vtbl, dshow_pin, QueryAccept); - SETVTBL(vtbl, dshow_pin, EnumMediaTypes); - SETVTBL(vtbl, dshow_pin, QueryInternalConnections); - SETVTBL(vtbl, dshow_pin, EndOfStream); - SETVTBL(vtbl, dshow_pin, BeginFlush); - SETVTBL(vtbl, dshow_pin, EndFlush); - SETVTBL(vtbl, dshow_pin, NewSegment); - - this->filter = filter; - - return 1; -} - -static inline void nothing(void *foo) -{ -} - -DECLARE_CREATE(dshow_pin, dshow_pin_setup(this, filter), dshow_filter *filter) -DECLARE_DESTROY(dshow_pin, nothing) - - -/***************************************************************************** - * dshow_input_pin - ****************************************************************************/ -long WINAPI dshow_input_pin_QueryInterface(dshow_input_pin *this, - const GUID *riid, void **ppvObject) -{ - struct dshow_pin *pin = (struct dshow_pin *) ((uint8_t *) this - imemoffset); - dshowdebug("dshow_input_pin_QueryInterface(%p)\n", this); - return dshow_pin_QueryInterface(pin, riid, ppvObject); -} - -unsigned long WINAPI dshow_input_pin_AddRef(dshow_input_pin *this) -{ - struct dshow_pin *pin = (struct dshow_pin *) ((uint8_t *) this - imemoffset); - dshowdebug("dshow_input_pin_AddRef(%p)\n", this); - return dshow_pin_AddRef(pin); -} - -unsigned long WINAPI dshow_input_pin_Release(dshow_input_pin *this) -{ - struct dshow_pin *pin = (struct dshow_pin *) ((uint8_t *) this - imemoffset); - dshowdebug("dshow_input_pin_Release(%p)\n", this); - return dshow_pin_Release(pin); -} - -long WINAPI dshow_input_pin_GetAllocator(dshow_input_pin *this, IMemAllocator **alloc) -{ - dshowdebug("dshow_input_pin_GetAllocator(%p)\n", this); - return VFW_E_NO_ALLOCATOR; -} - -long WINAPI dshow_input_pin_NotifyAllocator(dshow_input_pin *this, IMemAllocator *alloc, - BOOL rdwr) -{ - dshowdebug("dshow_input_pin_NotifyAllocator(%p)\n", this); - return S_OK; -} - -long WINAPI dshow_input_pin_GetAllocatorRequirements(dshow_input_pin *this, - ALLOCATOR_PROPERTIES *props) -{ - dshowdebug("dshow_input_pin_GetAllocatorRequirements(%p)\n", this); - return E_NOTIMPL; -} - -long WINAPI dshow_input_pin_Receive(dshow_input_pin *this, IMediaSample *sample) -{ - struct dshow_pin *pin = (struct dshow_pin *) ((uint8_t *) this - imemoffset); - void *priv_data; - uint8_t *buf; - int buf_size; /* todo should be a long? */ - int index; - int64_t curtime; - int64_t orig_curtime; - int64_t graphtime; - IReferenceClock *clock = pin->filter->clock; - int64_t dummy; - struct dshow_ctx *c; - - - dshowdebug("dshow_input_pin_Receive(%p)\n", this); - - if (!sample) - return E_POINTER; - - IMediaSample_GetTime(sample, &orig_curtime, &dummy); - orig_curtime += pin->filter->start_time; - IReferenceClock_GetTime(clock, &graphtime); - IReferenceClock_GetTime(clock, &curtime); - - buf_size = IMediaSample_GetActualDataLength(sample); - IMediaSample_GetPointer(sample, &buf); - priv_data = pin->filter->priv_data; - c = priv_data; - index = pin->filter->stream_index; - - pin->filter->callback(priv_data, index, buf, buf_size, curtime, 0); - - return S_OK; -} - -long WINAPI dshow_input_pin_ReceiveMultiple(dshow_input_pin *this, - IMediaSample **samples, long n, long *nproc) -{ - int i; - dshowdebug("dshow_input_pin_ReceiveMultiple(%p)\n", this); - - for (i = 0; i < n; i++) - dshow_input_pin_Receive(this, samples[i]); - - *nproc = n; - return S_OK; -} - -long WINAPI dshow_input_pin_ReceiveCanBlock(dshow_input_pin *this) -{ - dshowdebug("dshow_input_pin_ReceiveCanBlock(%p)\n", this); - /* I swear I will not block. */ - return S_FALSE; -} - -void dshow_input_pin_Destroy(dshow_input_pin *this) -{ - struct dshow_pin *pin = (struct dshow_pin *) ((uint8_t *) this - imemoffset); - dshowdebug("dshow_input_pin_Destroy(%p)\n", this); - dshow_pin_Destroy(pin); -} - -/***************************************************************************** - * dshow_enum_media - ****************************************************************************/ - -DECLARE_QUERYINTERFACE(dshow_enum_media_types, - { {&IID_IUnknown,0}, {&IID_IEnumMediaTypes,0} }) -DECLARE_ADDREF(dshow_enum_media_types) -DECLARE_RELEASE(dshow_enum_media_types) - -long WINAPI dshow_enum_media_types_Next(dshow_enum_media_types *this, unsigned long n, - AM_MEDIA_TYPE **types, unsigned long *fetched) -{ - int count = 0; - dshowdebug("dshow_enum_media_types_Next(%p)\n", this); - if (!types) - return E_POINTER; - if (!this->pos && n == 1) { - if (!IsEqualGUID(&this->type.majortype, &GUID_NULL)) { - AM_MEDIA_TYPE *type = malloc(sizeof(AM_MEDIA_TYPE)); - if (!type) - return E_OUTOFMEMORY; - copy_dshow_media_type(type, &this->type); - *types = type; - count = 1; - } - this->pos = 1; - } - if (fetched) - *fetched = count; - if (!count) - return S_FALSE; - return S_OK; -} - -long WINAPI dshow_enum_media_types_Skip(dshow_enum_media_types *this, unsigned long n) -{ - dshowdebug("dshow_enum_media_types_Skip(%p)\n", this); - if (n) /* Any skip will always fall outside of the only valid type. */ - return S_FALSE; - return S_OK; -} - -long WINAPI dshow_enum_media_types_Reset(dshow_enum_media_types *this) -{ - dshowdebug("dshow_enum_media_types_Reset(%p)\n", this); - this->pos = 0; - return S_OK; -} - - -long WINAPI dshow_enum_media_types_Clone(dshow_enum_media_types *this, dshow_enum_media_types **enums) -{ - dshow_enum_media_types *new; - dshowdebug("dshow_enum_media_types_Clone(%p)\n", this); - if (!enums) - return E_POINTER; - new = dshow_enum_media_types_Create(&this->type); - if (!new) - return E_OUTOFMEMORY; - new->pos = this->pos; - *enums = new; - return S_OK; -} - - -static int dshow_enum_media_types_Setup(dshow_enum_media_types *this, const AM_MEDIA_TYPE *type) -{ - IEnumMediaTypesVtbl *vtbl = this->vtbl; - SETVTBL(vtbl, dshow_enum_media_types, QueryInterface); - SETVTBL(vtbl, dshow_enum_media_types, AddRef); - SETVTBL(vtbl, dshow_enum_media_types, Release); - SETVTBL(vtbl, dshow_enum_media_types, Next); - SETVTBL(vtbl, dshow_enum_media_types, Skip); - SETVTBL(vtbl, dshow_enum_media_types, Reset); - SETVTBL(vtbl, dshow_enum_media_types, Clone); - - if (!type) { - this->type.majortype = GUID_NULL; - } else { - copy_dshow_media_type(&this->type, type); - } - - return 1; -} -DECLARE_CREATE(dshow_enum_media_types, dshow_enum_media_types_Setup(this, type), const AM_MEDIA_TYPE *type) -DECLARE_DESTROY(dshow_enum_media_types, nothing) -/***************************************************************************** - * xxxx - ****************************************************************************/ - -static int create_dshow_graph(struct dshow_ctx *c) -{ - int ret; - ret = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC, - &IID_IGraphBuilder, (void **)&c->graph); - if (FAILED(ret)) { - printf("CoCreateInstance IID_IGraphBuilder failed!\n"); - goto exit; - } - - ret = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, - &IID_ICaptureGraphBuilder2, (void **)&c->capgraph); - if (FAILED(ret)) { - printf("CoCreateInstance IID_ICaptureGraphBuilder2 failed!\n"); - goto exit; - } - - ret = ICaptureGraphBuilder2_SetFiltergraph(c->capgraph, c->graph); - if (FAILED(ret)) { - printf("Could not set graph for CaptureGraphBuilder2\n"); - goto exit; - } - - ret = IGraphBuilder_QueryInterface(c->graph, &IID_IMediaControl, - (void **)&c->mctrl); - if (FAILED(ret)) { - printf("QueryInterface IID_IMediaControl failed\n"); - goto exit; - } - -exit: - return ret; -} - -static int find_device(struct dshow_ctx *c) -{ - int ret; - ICreateDevEnum *devenum = NULL; - IEnumMoniker *classenum = NULL; - IBaseFilter *device_filter = NULL; - IMoniker *m = NULL; - - ret = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, - &IID_ICreateDevEnum, (void **)&devenum); - if (FAILED(ret)) { - printf("CoCreateInstance IID_ICreateDevEnum failed!\n"); - goto exit; - } - - ret = ICreateDevEnum_CreateClassEnumerator(devenum, &CLSID_VideoInputDeviceCategory, - (IEnumMoniker **)&classenum, 0); - if (FAILED(ret)) { - printf("failed to create class enumerator\n"); - goto exit; - } - - while (!device_filter && IEnumMoniker_Next(classenum, 1, &m, NULL) == S_OK) { - IPropertyBag *bag = NULL; - char *friendly_name = NULL; - char *unique_name = NULL; - VARIANT var; - IBindCtx *bind_ctx = NULL; - LPOLESTR olestr = NULL; - LPMALLOC co_malloc = NULL; - - ret = CoGetMalloc(1, &co_malloc); - if (ret != S_OK) - goto fail1; - ret = CreateBindCtx(0, &bind_ctx); - if (ret != S_OK) - goto fail1; - - ret = IMoniker_GetDisplayName(m, bind_ctx, NULL, &olestr); - if (ret != S_OK) - goto fail1; - unique_name = dup_wchar_to_utf8(olestr); - ret = IMoniker_BindToStorage(m, 0, 0, &IID_IPropertyBag, (void *)&bag); - if (ret != S_OK) - goto fail1; - - var.vt = VT_BSTR; - ret = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL); - if (ret != S_OK) - goto fail1; - friendly_name = dup_wchar_to_utf8(var.bstrVal); - - ret = IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (void *)&device_filter); - if (ret != S_OK) { - printf("Unable to BindToObject for %s\n", c->name); - goto fail1; - } - c->unique_name = strdup(unique_name); - - printf("friendly_name=\"%s\"\n", friendly_name); - //printf("unique_name=\"%s\"\n", unique_name); - free(unique_name); - -fail1: - if (olestr && co_malloc) - IMalloc_Free(co_malloc, olestr); - if (bind_ctx) - IBindCtx_Release(bind_ctx); - free(friendly_name); - if (bag) - IPropertyBag_Release(bag); - IMoniker_Release(m); - } - IEnumMoniker_Release(classenum); - if (device_filter) { - c->dev_filter = device_filter; - } - -exit: - return ret; -} - -static int enum_device(struct dshow_ctx *c) -{ - int ret; - IEnumPins *pins = NULL; - IPin *device_pin = NULL; - IPin *pin; - - ret = IBaseFilter_EnumPins(c->dev_filter, &pins); - if (ret != S_OK) { - printf("Could not enumerate pins.\n"); - goto exit; - } - - while (!device_pin && IEnumPins_Next(pins, 1, &pin, NULL) == S_OK) { - IKsPropertySet *p = NULL; - IEnumMediaTypes *types = NULL; - PIN_INFO info = {0}; - AM_MEDIA_TYPE *type; - GUID category; - DWORD r2; - wchar_t *pin_id = NULL; - char *pin_buf = NULL; - - IPin_QueryPinInfo(pin, &info); - IBaseFilter_Release(info.pFilter); - - if (info.dir != PINDIR_OUTPUT) - goto next; - if (IPin_QueryInterface(pin, &IID_IKsPropertySet, (void **) &p) != S_OK) - goto next; - if (IKsPropertySet_Get(p, &ROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, - NULL, 0, &category, sizeof(GUID), &r2) != S_OK) - goto next; - if (!IsEqualGUID(&category, &PIN_CATEGORY_CAPTURE)) - goto next; - - ret = IPin_QueryId(pin, &pin_id); - if (ret != S_OK) { - printf("Could not query pin id\n"); - goto exit; - } - pin_buf = dup_wchar_to_utf8(pin_id); - - if (IPin_EnumMediaTypes(pin, &types) != S_OK) - goto next; - IEnumMediaTypes_Reset(types); - - while (!device_pin && IEnumMediaTypes_Next(types, 1, &type, NULL) == S_OK) { - if (IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) { - device_pin = pin; - goto next; - } - CoTaskMemFree(type); - } - -next: - if (types) - IEnumMediaTypes_Release(types); - if (p) - IKsPropertySet_Release(p); - if (device_pin != pin) - IPin_Release(pin); - free(pin_buf); - if (pin_id) - CoTaskMemFree(pin_id); - } - IEnumPins_Release(pins); - if (!device_pin) { - printf("could not find capture device\n"); - ret = -1; - } else { - c->device_pin = device_pin; - } - -exit: - return ret; -} - -static void dshow_callback(void *priv_data, int index, uint8_t *buf, int buf_size, - int64_t time, int devtype) -{ - struct dshow_ctx *c = priv_data; - struct uvc_ctx *uvc = c->uvc; - struct video_frame *frame = &c->frame; - uint8_t *start; - int i; - - printf("%s index=%d, buf=%p, buf_size=%d, time=%lld, devtype=%d\n", __func__, - index, buf, buf_size, time, devtype); - frame->timestamp = time; - if (c->frame_id == 0) { - c->first_ts = frame->timestamp; - } - frame->timestamp -= c->first_ts; - frame->frame_id = c->frame_id; - if (frame->total_size != buf_size) { - printf("%s:%d warn: buf_size=%d, frame_size=%d, not matched!\n", __func__, __LINE__, - buf_size, frame->total_size); - } - c->frame_id++; - - start = buf; - if (uvc->on_video_frame) { - for (i = 0; i < frame->planes; ++i) { - frame->data[i] = start + frame->plane_offsets[i]; - } - uvc->on_video_frame(uvc, frame); - } -#if 0 - SetEvent(c->event[1]); -#endif - - return; -} - -static int open_device(struct dshow_ctx *c) -{ - int ret; - HANDLE media_event_handle; - HANDLE proc; - - c->cap_filter = dshow_filter_Create(c, dshow_callback, VideoDevice); - if (!c->cap_filter) { - printf("dshow_filter_Create failed!\n"); - goto exit; - } - - ret = IGraphBuilder_AddFilter(c->graph, c->dev_filter, NULL); - if (ret != S_OK) { - printf("Could not add device filter to graph.\n"); - goto exit; - } - - ret = IGraphBuilder_AddFilter(c->graph, (IBaseFilter *)c->cap_filter, NULL); - if (ret != S_OK) { - printf("Could not add device filter to graph.\n"); - goto exit; - } - - dshow_pin_AddRef(c->cap_filter->pin); - - ret = ICaptureGraphBuilder2_RenderStream(c->capgraph, NULL, NULL, - (IUnknown *)c->device_pin, NULL, (IBaseFilter *)c->cap_filter); - /* connect pins, optionally insert intermediate filters like crossbar if necessary */ - - if (ret != S_OK) { - printf("Could not RenderStream to connect pins\n"); - goto exit; - } - - c->mutex = CreateMutex(NULL, 0, NULL); - if (!c->mutex) { - printf("Could not create Mutex\n"); - goto exit; - } - c->event[1] = CreateEvent(NULL, 1, 0, NULL); - if (!c->event[1]) { - printf("Could not create Event\n"); - goto exit; - } - - ret = IGraphBuilder_QueryInterface(c->graph, &IID_IMediaControl, (void **)&c->mctrl); - if (ret != S_OK) { - printf("Could not get media control.\n"); - goto exit; - } - - ret = IGraphBuilder_QueryInterface(c->graph, &IID_IMediaEvent, (void **)&c->mevent); - if (ret != S_OK) { - printf("Could not get media event.\n"); - goto exit; - } - - ret = IMediaEvent_GetEventHandle(c->mevent, (void *)&media_event_handle); - if (ret != S_OK) { - printf("Could not get media event handle.\n"); - goto exit; - } - proc = GetCurrentProcess(); - ret = DuplicateHandle(proc, media_event_handle, proc, &c->event[0], - 0, 0, DUPLICATE_SAME_ACCESS); - if (!ret) { - printf("Could not duplicate media event handle.\n"); - goto exit; - } - - return 0; - -exit: - return ret; -} - -static void *dshow_open(struct uvc_ctx *uvc, const char *dev, struct uvc_config *conf) -{ - struct dshow_ctx *c = calloc(1, sizeof(struct dshow_ctx)); - if (!c) { - printf("malloc dshow_ctx failed!\n"); - return NULL; - } - c->name = strdup(dev); - c->width = conf->width; - c->height = conf->height; - c->fps_num = conf->fps.num;//unlimit fps - c->fps_den = conf->fps.den; - c->uvc = uvc; - c->frame_id = 0; - - CoInitialize(0); - - if (create_dshow_graph(c)) { - printf("create_dshow_graph failed!\n"); - goto exit; - } - if (find_device(c)) { - printf("find_device failed!\n"); - goto exit; - } - if (enum_device(c)) { - printf("enum_device failed\n"); - goto exit; - } - if (open_device(c)) { - printf("open_device failed!\n"); - goto exit; - } - - uvc->conf.width = c->width; - uvc->conf.height = c->height; - uvc->conf.fps.num = c->fps_num; - uvc->conf.fps.den = c->fps_den; - uvc->conf.format = conf->format; - uvc->fd = -1; - - video_frame_init(&c->frame, uvc->conf.format, uvc->conf.width, uvc->conf.height, MEDIA_MEM_SHALLOW); - return c; -exit: - if (c) - free(c); - return NULL; -} - -static void dshow_close(struct uvc_ctx *uvc) -{ - CoUninitialize(); -} - -static int dshow_dequeue(struct uvc_ctx *uvc, struct video_frame *frame) -{ - return 0; -} - -static int dshow_enqueue(struct uvc_ctx *uvc, void *buf, size_t len) -{ - return 0; -} - -static int dshow_ioctl(struct uvc_ctx *uvc, unsigned long int cmd, ...) -{ - return 0; -} - -static int dshow_start_stream(struct uvc_ctx *uvc) -{ - int ret; - struct dshow_ctx *c = (struct dshow_ctx *)uvc->opaque; - - ret = IMediaControl_Run(c->mctrl); - if (ret == S_FALSE) { - OAFilterState pfs; - ret = IMediaControl_GetState(c->mctrl, 0, &pfs); - return -1; - } - if (ret != S_OK) { - printf("Could not run graph (sometimes caused by a device already" - "in use by other application)\n"); - return -1; - } - return 0; -} - -static int dshow_stop_stream(struct uvc_ctx *uvc) -{ - int ret; - struct dshow_ctx *c = (struct dshow_ctx *)uvc->opaque; - IMediaControl_Stop(c->mctrl); - return 0; -} - -static int dshow_query_frame(struct uvc_ctx *uvc, struct video_frame *frame) -{ - return 0; -} - -struct uvc_ops dshow_ops = { - /*.open = */ dshow_open, - /*.close = */ dshow_close, - /*.ioctl = */ dshow_ioctl, - /*.start_stream= */ dshow_start_stream, - /*.stop_stream = */ dshow_stop_stream, - /*.query_frame = */ dshow_query_frame, -}; diff --git a/gear-lib/libuvc/dshow.h b/gear-lib/libuvc/dshow.h deleted file mode 100644 index b9ba163..0000000 --- a/gear-lib/libuvc/dshow.h +++ /dev/null @@ -1,245 +0,0 @@ -#ifndef DSHOW_H -#define DSHOW_H - -#define COBJMACROS -#define CINTERFACE -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -enum dshowDeviceType { - VideoDevice = 0, - AudioDevice = 1, -}; - - -//#define dshowdebug(...) printf(__VA_ARGS__) -#define dshowdebug(...) do{} while(0) - -struct GUIDoffset { - const GUID *iid; - int offset; -}; - -#define DECLARE_QUERYINTERFACE(class, ...) \ -long WINAPI class##_QueryInterface(class *this, const GUID *riid, void **ppobj) \ -{ \ - struct GUIDoffset ifaces[] = __VA_ARGS__; \ - int i; \ - dshowdebug("%s(%p, %p, %p)\n", __func__, this, riid, ppobj); \ - if (!ppobj) \ - return E_POINTER; \ - for (i = 0; i < sizeof(ifaces)/sizeof(ifaces[0]); i++) { \ - if (IsEqualGUID(riid, ifaces[i].iid)) { \ - void *obj = (void *) ((uint8_t *) this + ifaces[i].offset); \ - class##_AddRef(this); \ - *ppobj = (void *) obj; \ - return S_OK; \ - } \ - } \ - dshowdebug("%s(%p) E_NOINTERFACE\n", __func__, this, riid, ppobj); \ - *ppobj = NULL; \ - return E_NOINTERFACE; \ -} - -#define DECLARE_ADDREF(class) \ -unsigned long WINAPI \ -class##_AddRef(class *this) \ -{ \ - dshowdebug("%s(%p)\t%ld\n", __func__, this, this->ref+1); \ - return InterlockedIncrement(&this->ref); \ -} -#define DECLARE_RELEASE(class) \ -unsigned long WINAPI \ -class##_Release(class *this) \ -{ \ - long ref = InterlockedDecrement(&this->ref); \ - dshowdebug("%s(%p)\t%ld\n", __func__, this, ref); \ - if (!ref) \ - class##_Destroy(this); \ - return ref; \ -} - - -#define DECLARE_DESTROY(class, func) \ -void class##_Destroy(class *this) \ -{ \ - dshowdebug("%s(%p)\n", __func__, this); \ - func(this); \ - if (this) { \ - if (this->vtbl) \ - CoTaskMemFree(this->vtbl); \ - CoTaskMemFree(this); \ - } \ -} -#define DECLARE_CREATE(class, setup, ...) \ -class *class##_Create(__VA_ARGS__) \ -{ \ - class *this = CoTaskMemAlloc(sizeof(class)); \ - void *vtbl = CoTaskMemAlloc(sizeof(*this->vtbl)); \ - if (!this || !vtbl) \ - goto fail; \ - ZeroMemory(this, sizeof(class)); \ - ZeroMemory(vtbl, sizeof(*this->vtbl)); \ - this->ref = 1; \ - this->vtbl = vtbl; \ - if (!setup) \ - goto fail; \ - dshowdebug("%s(%p)\n", __func__, this); \ - return this; \ -fail: \ - class##_Destroy(this); \ - dshowdebug("could not create \n"); \ - return NULL; \ -} - -#define SETVTBL(vtbl, class, fn) \ - do { (vtbl)->fn = (void *) class##_##fn; } while(0) - -#define imemoffset offsetof(dshow_pin, imemvtbl) - -/***************************************************************************** - * dshow_pin - ****************************************************************************/ -typedef struct dshow_pin dshow_pin; -typedef struct dshow_filter dshow_filter; -typedef struct dshow_enum_pins dshow_enum_pins; -typedef struct dshow_enum_media_types dshow_enum_media_types; -typedef struct dshow_input_pin dshow_input_pin; - -struct dshow_pin { - IPinVtbl *vtbl; - IMemInputPinVtbl *imemvtbl; - IPin *connectedto; - struct dshow_filter *filter; - AM_MEDIA_TYPE type; - long ref; -}; - -struct dshow_filter { - IBaseFilterVtbl *vtbl; - long ref; - const wchar_t *name; - struct dshow_pin *pin; - FILTER_INFO info; - FILTER_STATE state; - IReferenceClock *clock; - void *priv_data; - int stream_index; - int64_t start_time; - void (*callback)(void *priv, int index, uint8_t *buf, int size, int64_t time, int devtype); -}; - - -long WINAPI dshow_pin_QueryInterface (dshow_pin *, const GUID *, void **); -unsigned long WINAPI dshow_pin_AddRef (dshow_pin *); -unsigned long WINAPI dshow_pin_Release (dshow_pin *); -long WINAPI dshow_pin_Connect (dshow_pin *, IPin *, const AM_MEDIA_TYPE *); -long WINAPI dshow_pin_ReceiveConnection (dshow_pin *, IPin *, const AM_MEDIA_TYPE *); -long WINAPI dshow_pin_Disconnect (dshow_pin *); -long WINAPI dshow_pin_ConnectedTo (dshow_pin *, IPin **); -long WINAPI dshow_pin_ConnectionMediaType (dshow_pin *, AM_MEDIA_TYPE *); -long WINAPI dshow_pin_QueryPinInfo (dshow_pin *, PIN_INFO *); -long WINAPI dshow_pin_QueryDirection (dshow_pin *, PIN_DIRECTION *); -long WINAPI dshow_pin_QueryId (dshow_pin *, wchar_t **); -long WINAPI dshow_pin_QueryAccept (dshow_pin *, const AM_MEDIA_TYPE *); -long WINAPI dshow_pin_EnumMediaTypes (dshow_pin *, IEnumMediaTypes **); -long WINAPI dshow_pin_QueryInternalConnections(dshow_pin *, IPin **, unsigned long *); -long WINAPI dshow_pin_EndOfStream (dshow_pin *); -long WINAPI dshow_pin_BeginFlush (dshow_pin *); -long WINAPI dshow_pin_EndFlush (dshow_pin *); -long WINAPI dshow_pin_NewSegment (dshow_pin *, REFERENCE_TIME, REFERENCE_TIME, double); -dshow_pin *dshow_pin_Create (dshow_filter *filter); -void dshow_pin_Destroy(dshow_pin *); - -/***************************************************************************** - * dshow_input_pin - ****************************************************************************/ -long WINAPI dshow_input_pin_QueryInterface (dshow_input_pin *, const GUID *, void **); -unsigned long WINAPI dshow_input_pin_AddRef (dshow_input_pin *); -unsigned long WINAPI dshow_input_pin_Release (dshow_input_pin *); -long WINAPI dshow_input_pin_GetAllocator (dshow_input_pin *, IMemAllocator **); -long WINAPI dshow_input_pin_NotifyAllocator (dshow_input_pin *, IMemAllocator *, BOOL); -long WINAPI dshow_input_pin_GetAllocatorRequirements(dshow_input_pin *, ALLOCATOR_PROPERTIES *); -long WINAPI dshow_input_pin_Receive (dshow_input_pin *, IMediaSample *); -long WINAPI dshow_input_pin_ReceiveMultiple (dshow_input_pin *, IMediaSample **, long, long *); -long WINAPI dshow_input_pin_ReceiveCanBlock (dshow_input_pin *); -void dshow_input_pin_Destroy(dshow_input_pin *); - -/***************************************************************************** - * dshow_enum_media_types - ****************************************************************************/ -struct dshow_enum_media_types { - IEnumMediaTypesVtbl *vtbl; - long ref; - int pos; - AM_MEDIA_TYPE type; -}; - -long WINAPI dshow_enum_media_types_QueryInterface(dshow_enum_media_types *, const GUID *, void **); -unsigned long WINAPI dshow_enum_media_types_AddRef (dshow_enum_media_types *); -unsigned long WINAPI dshow_enum_media_types_Release (dshow_enum_media_types *); -long WINAPI dshow_enum_media_types_Next (dshow_enum_media_types *, unsigned long, AM_MEDIA_TYPE **, unsigned long *); -long WINAPI dshow_enum_media_types_Skip (dshow_enum_media_types *, unsigned long); -long WINAPI dshow_enum_media_types_Reset (dshow_enum_media_types *); -long WINAPI dshow_enum_media_types_Clone (dshow_enum_media_types *, dshow_enum_media_types **); - -void dshow_enum_media_types_Destroy(dshow_enum_media_types *); -dshow_enum_media_types *dshow_enum_media_types_Create(const AM_MEDIA_TYPE *type); - -/***************************************************************************** - * dshow_filter - ****************************************************************************/ -long WINAPI dshow_filter_QueryInterface (dshow_filter *, const GUID *, void **); -unsigned long WINAPI dshow_filter_AddRef (dshow_filter *); -unsigned long WINAPI dshow_filter_Release (dshow_filter *); -long WINAPI dshow_filter_GetClassID (dshow_filter *, CLSID *); -long WINAPI dshow_filter_Stop (dshow_filter *); -long WINAPI dshow_filter_Pause (dshow_filter *); -long WINAPI dshow_filter_Run (dshow_filter *, REFERENCE_TIME); -long WINAPI dshow_filter_GetState (dshow_filter *, DWORD, FILTER_STATE *); -long WINAPI dshow_filter_SetSyncSource (dshow_filter *, IReferenceClock *); -long WINAPI dshow_filter_GetSyncSource (dshow_filter *, IReferenceClock **); -long WINAPI dshow_filter_EnumPins (dshow_filter *, IEnumPins **); -long WINAPI dshow_filter_FindPin (dshow_filter *, const wchar_t *, IPin **); -long WINAPI dshow_filter_QueryFilterInfo(dshow_filter *, FILTER_INFO *); -long WINAPI dshow_filter_JoinFilterGraph(dshow_filter *, IFilterGraph *, const wchar_t *); -long WINAPI dshow_filter_QueryVendorInfo(dshow_filter *, wchar_t **); - -void dshow_filter_Destroy(dshow_filter *); -dshow_filter *dshow_filter_Create (void *, void *, enum dshowDeviceType); - - -/***************************************************************************** - * dshow_enum_pins - ****************************************************************************/ -struct dshow_enum_pins { - IEnumPinsVtbl *vtbl; - long ref; - int pos; - dshow_pin *pin; - dshow_filter *filter; -}; - -long WINAPI dshow_enum_pins_QueryInterface(dshow_enum_pins *, const GUID *, void **); -unsigned long WINAPI dshow_enum_pins_AddRef (dshow_enum_pins *); -unsigned long WINAPI dshow_enum_pins_Release (dshow_enum_pins *); -long WINAPI dshow_enum_pins_Next (dshow_enum_pins *, unsigned long, IPin **, unsigned long *); -long WINAPI dshow_enum_pins_Skip (dshow_enum_pins *, unsigned long); -long WINAPI dshow_enum_pins_Reset (dshow_enum_pins *); -long WINAPI dshow_enum_pins_Clone (dshow_enum_pins *, dshow_enum_pins **); - -void dshow_enum_pins_Destroy(dshow_enum_pins *); -dshow_enum_pins *dshow_enum_pins_Create (dshow_pin *pin, dshow_filter *filter); - - -#endif diff --git a/gear-lib/libuvc/dummy.c b/gear-lib/libuvc/dummy.c deleted file mode 100644 index 67111cb..0000000 --- a/gear-lib/libuvc/dummy.c +++ /dev/null @@ -1,339 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2014-2020 Zhifeng Gong - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - ******************************************************************************/ -#include "libuvc.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct dummy_ctx { - int fd; - int ev_fd; - uint64_t seek_offset; - uint64_t file_size_total; - uint64_t first_ts; - uint64_t frame_id; - struct uvc_ctx *parent; - struct thread *thread; - bool is_streaming; - int epfd; - struct epoll_event events; -}; - -#define timespec2ns(ts) \ - (((uint64_t)ts.tv_sec * 1000000000) + ((uint64_t)ts.tv_nsec)) - -static ssize_t get_file_size(const char *path) -{ - struct stat st; - off_t size = 0; - if (!path) { - return -1; - } - if (stat(path, &st) < 0) { - printf("%s stat error: %s\n", path, strerror(errno)); - } else { - size = st.st_size; - } - return size; -} - -static void *uvc_dummy_open(struct uvc_ctx *uvc, const char *dev, struct uvc_config *conf) -{ - struct dummy_ctx *c = calloc(1, sizeof(struct dummy_ctx)); - if (!c) { - printf("malloc dummy_ctx failed!\n"); - return NULL; - } - - c->fd = open(dev, O_RDWR); - if (c->fd == -1) { - printf("open %s failed: %d\n", dev, errno); - goto failed; - } - c->frame_id = 0; - c->seek_offset = 0; - c->ev_fd = eventfd(0, 0); - if (c->ev_fd == -1) { - printf("eventfd failed %d\n", errno); - goto failed; - } - c->file_size_total = get_file_size(dev); - - memcpy(&uvc->conf, conf, sizeof(struct uvc_config)); - c->parent = uvc; - - return c; - -failed: - if (c->fd != -1) { - close(c->fd); - } - if (c) { - free(c); - } - return NULL; -} - -static int msleep(uint64_t ms) -{ - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = ms*1000; - return select(0, NULL, NULL, NULL, &tv); -} - -static int uvc_dummy_enqueue(struct uvc_ctx *uvc, void *buf, size_t len) -{ - uint64_t notify = '1'; - uint64_t delay_ms = 0; - struct dummy_ctx *c = (struct dummy_ctx *)uvc->opaque; - - delay_ms = (1000)/(uvc->conf.fps.num/(uvc->conf.fps.den*1.0)); - msleep(delay_ms); - if (write(c->ev_fd, ¬ify, sizeof(uint64_t)) != sizeof(uint64_t)) { - printf("%s failed to notify ev_fd=%d, %d\n", __func__, c->ev_fd, errno); - return -1; - } - return 0; -} - -static int uvc_dummy_dequeue(struct uvc_ctx *uvc, struct video_frame *frame) -{ - int i; - ssize_t ret; - size_t len; - uint64_t notify; - struct timespec ts; - struct dummy_ctx *c = (struct dummy_ctx *)uvc->opaque; - - if (read(c->ev_fd, ¬ify, sizeof(notify)) != sizeof(uint64_t)) { - printf("failed to read from notify %d\n", errno); - return -1; - } - - for (i = 0; i < frame->planes; ++i) { - len = frame->linesize[i]*frame->height; - ret = read(c->fd, frame->data[i], len); - if (ret != len) { - printf("read failed: ret=%zd, len=%zu, errno=%d, ptr=%p\n", ret, len, errno, frame->data[i]); - return -1; - } - c->seek_offset += len; - if (c->seek_offset > c->file_size_total) { - printf("read file exceed total file size\n"); - return -1; - } - lseek(c->fd, c->seek_offset, SEEK_SET); - } - if (-1 == clock_gettime(CLOCK_REALTIME, &ts)) { - printf("clock_gettime failed %d:%s\n", errno, strerror(errno)); - return -1; - } - frame->timestamp = timespec2ns(ts); - if (c->frame_id == 0) { - c->first_ts = frame->timestamp; - } - frame->timestamp -= c->first_ts; - frame->frame_id = c->frame_id; - c->frame_id++; - - return frame->total_size; -} - -static int uvc_dummy_poll_init(struct dummy_ctx *c) -{ - struct epoll_event epev; - memset(&epev, 0, sizeof(epev)); - printf("dummy_ctx=%p\n", c); - c->epfd = epoll_create(1); - if (c->epfd == -1) { - printf("epoll_create failed %d!\n", errno); - return -1; - } - - epev.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET | EPOLLERR; - epev.data.ptr = (void *)c; - if (-1 == epoll_ctl(c->epfd, EPOLL_CTL_ADD, c->ev_fd, &epev)) { - printf("epoll_ctl EPOLL_CTL_ADD failed %d!\n", errno); - return -1; - } - return 0; -} - -static int uvc_dummy_poll(struct uvc_ctx *uvc, int timeout) -{ - struct dummy_ctx *c = (struct dummy_ctx *)uvc->opaque; - int ret = 0; - - int n = epoll_wait(c->epfd, &c->events, 1, timeout); - switch (n) { - case 0: - printf("poll timeout\n"); - ret = -1; - break; - case -1: - printf("poll error %d\n", errno); - ret = -1; - break; - default: - ret = 0; - break; - } - - return ret; -} - -static void uvc_dummy_poll_deinit(struct dummy_ctx *c) -{ - if (-1 == epoll_ctl(c->epfd, EPOLL_CTL_DEL, c->ev_fd, NULL)) { - printf("epoll_ctl EPOLL_CTL_DEL failed %d!\n", errno); - } - close(c->epfd); -} - -static void *dummy_thread(struct thread *t, void *arg) -{ - struct uvc_ctx *uvc = arg; - struct dummy_ctx *c = (struct dummy_ctx *)uvc->opaque; - struct video_frame *frame; - - if (uvc_dummy_poll_init(c) == -1) { - printf("uvc_dummy_poll_init failed!\n"); - } - frame = video_frame_create(uvc->conf.format, uvc->conf.width, uvc->conf.height, MEDIA_MEM_DEEP); - if (!frame) { - printf("video_frame_create failed!\n"); - return NULL; - } - c->is_streaming = true; - while (c->is_streaming) { - if (uvc_dummy_enqueue(uvc, NULL, 0) != 0) { - printf("uvc_dummy_enqueue failed\n"); - continue; - } - if (uvc_dummy_poll(uvc, -1) != 0) { - printf("uvc_dummy_poll failed\n"); - continue; - } - - if (uvc_dummy_dequeue(uvc, frame) == -1) { - printf("uvc_dummy_dequeue failed\n"); - break; - } - uvc->on_video_frame(uvc, frame); - } - video_frame_destroy(frame); - uvc_dummy_poll_deinit(c); - return NULL; -} - -static int uvc_dummy_start_stream(struct uvc_ctx *uvc) -{ - uint64_t notify = '1'; - struct dummy_ctx *c = (struct dummy_ctx *)uvc->opaque; - - if (c->is_streaming) { - printf("dummy is streaming already!\n"); - return -1; - } - - if (write(c->ev_fd, ¬ify, sizeof(uint64_t)) != sizeof(uint64_t)) { - printf("%s failed to notify ev_fd=%d, %d\n", __func__, c->ev_fd, errno); - return -1; - } - - if (uvc->on_video_frame) { - c->thread = thread_create(dummy_thread, uvc); - } - - return 0; -} - -static int uvc_dummy_stop_stream(struct uvc_ctx *uvc) -{ - struct dummy_ctx *c = (struct dummy_ctx *)uvc->opaque; - uint64_t notify = '1'; - - if (!c->is_streaming) { - printf("dummy stream stopped already!\n"); - return -1; - } - - if (write(c->ev_fd, ¬ify, sizeof(uint64_t)) != sizeof(uint64_t)) { - printf("%s failed to notify ev_fd=%d, %d\n", __func__, c->ev_fd, errno); - return -1; - } - - if (uvc->on_video_frame) { - c->is_streaming = false; - thread_join(c->thread); - thread_destroy(c->thread); - } - - return 0; -} - -static int uvc_dummy_query_frame(struct uvc_ctx *uvc, struct video_frame *frame) -{ - if (uvc_dummy_enqueue(uvc, NULL, 0) != 0) { - printf("uvc_dummy_enqueue failed\n"); - return -1; - } - if (uvc_dummy_dequeue(uvc, frame) == -1) { - printf("uvc_dummy_dequeue failed\n"); - return -1; - } - return 0; -} - -static int uvc_dummy_ioctl(struct uvc_ctx *uvc, unsigned long int cmd, ...) -{ - printf("uvc_dummy_ioctl unsupport cmd!\n"); - return -1; -} - -static void uvc_dummy_close(struct uvc_ctx *uvc) -{ - struct dummy_ctx *c = (struct dummy_ctx *)uvc->opaque; - uvc_dummy_stop_stream(uvc); - close(c->fd); - close(c->epfd); - close(c->ev_fd); - free(c); -} - -struct uvc_ops dummy_ops = { - ._open = uvc_dummy_open, - ._close = uvc_dummy_close, - .ioctl = uvc_dummy_ioctl, - .start_stream = uvc_dummy_start_stream, - .stop_stream = uvc_dummy_stop_stream, - .query_frame = uvc_dummy_query_frame, -}; diff --git a/gear-lib/libuvc/libuvc.c b/gear-lib/libuvc/libuvc.c deleted file mode 100644 index be598fe..0000000 --- a/gear-lib/libuvc/libuvc.c +++ /dev/null @@ -1,165 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2014-2020 Zhifeng Gong - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - ******************************************************************************/ -#include "libuvc.h" -#include -#include -#include -#include -#include -#include -#include - -#if defined (OS_LINUX) -extern struct uvc_ops dummy_ops; -extern struct uvc_ops v4l2_ops; -extern struct uvc_ops ucam_ops; -#elif defined (OS_WINDOWS) -extern struct uvc_ops dshow_ops; -#endif - -enum uvc_type { -#if defined (OS_LINUX) - UVC_TYPE_DUMMY, - UVC_TYPE_V4L2, - UVC_TYPE_UCAM, -#elif defined (OS_WINDOWS) - UVC_TYPE_DSHOW, -#endif - UVC_TYPE_MAX, -}; - -static struct uvc_ops *uvc_ops[] = { -#if defined (OS_LINUX) - &dummy_ops, - &v4l2_ops, - &ucam_ops, -#elif defined (OS_WINDOWS) - &dshow_ops, -#endif - NULL, -}; - -struct uvc_ctx *uvc_open(const char *dev, struct uvc_config *conf) -{ - enum uvc_type type; - struct uvc_ctx *uvc; -#if defined (OS_LINUX) - type = UVC_TYPE_V4L2; - //type = UVC_TYPE_UCAM; -#elif defined (OS_WINDOWS) - type = UVC_TYPE_DSHOW; -#endif - if (!dev) { - type = UVC_TYPE_DUMMY; - dev = conf->dev_name; - printf("%s:%d open dummy device\n", __func__, __LINE__); - } - if (!conf) { - printf("%s:%d invalid paraments!\n", __func__, __LINE__); - return NULL; - } - uvc = (struct uvc_ctx *)calloc(1, sizeof(struct uvc_ctx)); - if (!uvc) { - printf("malloc failed!\n"); - return NULL; - } - uvc->ops = uvc_ops[type]; - if (!uvc->ops) { - printf("uvc->ops %d is NULL!\n", type); - return NULL; - } - uvc->opaque = uvc->ops->_open(uvc, dev, conf); - if (!uvc->opaque) { - printf("open %s failed!\n", dev); - goto failed; - } - return uvc; -failed: - free(uvc); - return NULL; -} - -int uvc_query_frame(struct uvc_ctx *uvc, struct video_frame *frame) -{ - if (!uvc || !frame) { - printf("%s:%d invalid paraments!\n", __func__, __LINE__); - return -1; - } - return uvc->ops->query_frame(uvc, frame); -} - -int uvc_start_stream(struct uvc_ctx *uvc, video_frame_cb *cb) -{ - if (!uvc) { - printf("%s:%d invalid paraments!\n", __func__, __LINE__); - return -1; - } - uvc->on_video_frame = cb; - return uvc->ops->start_stream(uvc); -} - -int uvc_stop_stream(struct uvc_ctx *uvc) -{ - if (!uvc) { - printf("%s:%d invalid paraments!\n", __func__, __LINE__); - return -1; - } - return uvc->ops->stop_stream(uvc); -} - -int uvc_ioctl(struct uvc_ctx *uvc, unsigned long int cmd, ...) -{ - int ret; - void *arg; - va_list ap; - va_start(ap, cmd); - arg = va_arg(ap, void *); - va_end(ap); - - switch (cmd) { - case UVC_GET_CAP: - ret = uvc->ops->ioctl(uvc, cmd, NULL); - break; - case UVC_SET_CTRL: { - struct video_ctrl *vctrl; - vctrl = (struct video_ctrl *)arg; - ret = uvc->ops->ioctl(uvc, vctrl->cmd, vctrl->val); - } break; - case UVC_SET_CONF: { - ret = uvc->ops->ioctl(uvc, cmd, (struct uvc_config *)arg); - } break; - default: - ret = uvc->ops->ioctl(uvc, cmd, arg); - break; - } - return ret; -} - -void uvc_close(struct uvc_ctx *uvc) -{ - if (!uvc) { - printf("%s:%d invalid paraments!\n", __func__, __LINE__); - return; - } - uvc->ops->_close(uvc); - free(uvc); -} diff --git a/gear-lib/libuvc/libuvc.h b/gear-lib/libuvc/libuvc.h deleted file mode 100644 index dc9615f..0000000 --- a/gear-lib/libuvc/libuvc.h +++ /dev/null @@ -1,127 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2014-2020 Zhifeng Gong - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - ******************************************************************************/ -#ifndef LIBUVC_H -#define LIBUVC_H - -#include -#include -#include -#include -#if defined (OS_LINUX) -#define __USE_LINUX_IOCTL_DEFS -#include -#endif - -#define LIBUVC_VERSION "0.2.1" - -#ifdef __cplusplus -extern "C" { -#endif - -struct uvc_ctx; -struct uvc_ops; -typedef int (video_frame_cb)(struct uvc_ctx *c, struct video_frame *frame); - -struct uvc_config { - uint32_t width; - uint32_t height; - rational_t fps; - enum pixel_format format; - char *dev_name; -}; - -struct uvc_image_quality { - int brightness; - int contrast; - int saturation; - int hue; - int awb; - int gamma; - int sharpness; -}; - -struct uvc_ctx { - int fd; - struct uvc_config conf; - struct uvc_ops *ops; - video_frame_cb *on_video_frame; - void *opaque; -}; - -struct video_cap { - uint8_t desc[32]; - uint32_t version; -}; - -struct video_ctrl { - uint32_t cmd; - uint32_t val; -}; - -#define UVC_GET_CAP _IOWR('V', 0, struct video_cap) -#define UVC_SET_CTRL _IOWR('V', 1, struct video_ctrl) -#define UVC_SET_CONF _IOWR('V', 2, struct uvc_config) -#define UVC_GET_LUMA _IOWR('V', 3, int *) -#define UVC_SET_LUMA _IOWR('V', 4, int) -#define UVC_GET_CTRST _IOWR('V', 5, int *) -#define UVC_SET_CTRST _IOWR('V', 6, int) -#define UVC_GET_SAT _IOWR('V', 7, int *) -#define UVC_SET_SAT _IOWR('V', 8, int) -#define UVC_GET_HUE _IOWR('V', 9, int *) -#define UVC_SET_HUE _IOWR('V', 10, int) -#define UVC_GET_AWB _IOWR('V', 11, int *) -#define UVC_SET_AWB _IOWR('V', 12, int) -#define UVC_GET_GAMMA _IOWR('V', 13, int *) -#define UVC_SET_GAMMA _IOWR('V', 14, int) -#define UVC_GET_SHARP _IOWR('V', 15, int *) -#define UVC_SET_SHARP _IOWR('V', 16, int) - - - -struct uvc_ops { - void *(*_open)(struct uvc_ctx *uvc, const char *dev, struct uvc_config *conf); - void (*_close)(struct uvc_ctx *c); - int (*ioctl)(struct uvc_ctx *c, unsigned long int cmd, ...); - int (*start_stream)(struct uvc_ctx *c); - int (*stop_stream)(struct uvc_ctx *c); - int (*query_frame)(struct uvc_ctx *c, struct video_frame *frame); -}; - -GEAR_API struct uvc_ctx *uvc_open(const char *dev, struct uvc_config *conf); -GEAR_API int uvc_ioctl(struct uvc_ctx *c, unsigned long int cmd, ...); -GEAR_API void uvc_close(struct uvc_ctx *c); - -/* - * active query frame one by one - */ -GEAR_API int uvc_query_frame(struct uvc_ctx *c, struct video_frame *frame); - -/* - * passive get frame when cb is set, otherwise need query frame one by one - */ -GEAR_API int uvc_start_stream(struct uvc_ctx *uvc, video_frame_cb *cb); -GEAR_API int uvc_stop_stream(struct uvc_ctx *uvc); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gear-lib/libuvc/test_libuvc.c b/gear-lib/libuvc/test_libuvc.c deleted file mode 100644 index e57f559..0000000 --- a/gear-lib/libuvc/test_libuvc.c +++ /dev/null @@ -1,134 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2014-2020 Zhifeng Gong - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - ******************************************************************************/ -#include "libuvc.h" -#include -#include -#include -#include -#include -#define __STDC_FORMAT_MACROS -#include - -#define VIDEO_DEV "/dev/video0" -#define VIDEO_WIDTH 640 -#define VIDEO_HEIGHT 480 -#define OUTPUT_V4L2 "v4l2.yuv" -#define OUTPUT_DUMMY "dummy.yuv" - -static struct file *fp; - -static int on_frame(struct uvc_ctx *c, struct video_frame *frm) -{ - static uint64_t last_ms = 0; - static int luma = 0; - static int i = 0; - - printf("frm[%" PRIu64 "] size=%" PRIu64 ", ts=%" PRIu64 " ms, gap=%" PRIu64 " ms\n", - frm->frame_id, frm->total_size, frm->timestamp/1000000, frm->timestamp/1000000 - last_ms); - last_ms = frm->timestamp/1000000; - luma = 2 * i++; - luma *= i%2 ? 1: -1; - uvc_ioctl(c, UVC_SET_LUMA, luma); - file_write(fp, frm->data[0], frm->total_size); - return 0; -} - -int v4l2_test() -{ - struct uvc_ctx *uvc; - struct video_frame *frm; - struct uvc_config conf = { - VIDEO_WIDTH, - VIDEO_HEIGHT, - {30, 1}, - PIXEL_FORMAT_YUY2, - }; - uvc = uvc_open(VIDEO_DEV, &conf); - if (!uvc) { - printf("uvc_open failed!\n"); - return -1; - } - //uvc_ioctl(uvc, UVC_SET_CONF, &conf); - uvc_ioctl(uvc, UVC_GET_CAP, NULL); - frm = video_frame_create(uvc->conf.format, uvc->conf.width, uvc->conf.height, MEDIA_MEM_SHALLOW); - if (!frm) { - printf("video_frame_create failed!\n"); - uvc_close(uvc); - return -1; - } - printf("uvc info: %s %dx%d@%d/%d fps format:%s\n", VIDEO_DEV, uvc->conf.width, uvc->conf.height, - uvc->conf.fps.num, uvc->conf.fps.den, pixel_format_to_string(uvc->conf.format)); - fp = file_open(OUTPUT_V4L2, F_CREATE); - uvc_start_stream(uvc, on_frame); - - sleep(5); - uvc_stop_stream(uvc); - file_close(fp); - video_frame_destroy(frm); - uvc_close(uvc); - printf("write %s fininshed!\n", OUTPUT_V4L2); - return 0; -} - -int dummy_test() -{ -#if defined (OS_LINUX) - struct video_frame *frm; - struct uvc_config conf = { - 320, - 240, - {30, 1}, - PIXEL_FORMAT_YUY2, - "sample_320x240_yuv422p.yuv", - }; - struct uvc_ctx *uvc = uvc_open(NULL, &conf); - if (!uvc) { - printf("uvc_open failed!\n"); - return -1; - } - frm = video_frame_create(uvc->conf.format, uvc->conf.width, uvc->conf.height, MEDIA_MEM_SHALLOW); - if (!frm) { - printf("video_frame_create failed!\n"); - uvc_close(uvc); - return -1; - } - printf("%s %dx%d@%d/%d fps format:%s\n", VIDEO_DEV, uvc->conf.width, uvc->conf.height, - uvc->conf.fps.num, uvc->conf.fps.den, pixel_format_to_string(uvc->conf.format)); - fp = file_open(OUTPUT_DUMMY, F_CREATE); - uvc_start_stream(uvc, on_frame); - sleep(5); - uvc_stop_stream(uvc); - file_sync(fp); - file_close(fp); - video_frame_destroy(frm); - uvc_close(uvc); - printf("write %s fininshed!\n", OUTPUT_DUMMY); -#endif - return 0; -} - -int main(int argc, char **argv) -{ - v4l2_test(); - dummy_test(); - return 0; -} diff --git a/gear-lib/libuvc/usbcam.c b/gear-lib/libuvc/usbcam.c deleted file mode 100644 index f060b3e..0000000 --- a/gear-lib/libuvc/usbcam.c +++ /dev/null @@ -1,1123 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2014-2020 Zhifeng Gong - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - ******************************************************************************/ -#include "libuvc.h" -#include -#include -#include -#include "usbcam.h" - -struct ucam_ctx { - struct ucam_dev_info dev_info; - struct libusb_context *usb_ctx; - struct libusb_device *usb_dev; - struct libusb_device_handle *usb_devh; - struct libusb_transfer *usb_xfer; - struct ucam_stream_handle *strmh; - uvc_status_callback_t *status_cb; - void *status_user_ptr; - uvc_button_callback_t *button_cb; - void *button_user_ptr; - uint8_t status_buf[32]; - uint32_t claimed; - pthread_t tid; - int thread_run; -}; - - -static int ucam_parse_vs(struct ucam_ctx *c, struct ucam_dev_info *info, - struct ucam_stream *stream, - const unsigned char *block, size_t block_size) -{ - int ret; - int descriptor_subtype; - const unsigned char *p; - int i; - - ret = 0; - descriptor_subtype = block[2]; - - switch (descriptor_subtype) { - case UVC_VS_INPUT_HEADER: - stream->bEndpointAddress = block[6] & 0x8f; - stream->bTerminalLink = block[8]; - break; - case UVC_VS_OUTPUT_HEADER: - printf("unsupported descriptor subtype VS_OUTPUT_HEADER\n"); - break; - case UVC_VS_STILL_IMAGE_FRAME: - printf("unsupported descriptor subtype VS_STILL_IMAGE_FRAME\n"); - break; - case UVC_VS_FORMAT_UNCOMPRESSED: - info->format.bDescriptorSubtype = block[2]; - info->format.bFormatIndex = block[3]; - //info->format.bmCapabilities = block[4]; - //info->format.bmFlags = block[5]; - memcpy(info->format.guidFormat, &block[5], 16); - info->format.bBitsPerPixel = block[21]; - info->format.bDefaultFrameIndex = block[22]; - info->format.bAspectRatioX = block[23]; - info->format.bAspectRatioY = block[24]; - info->format.bmInterlaceFlags = block[25]; - info->format.bCopyProtect = block[26]; - break; - case UVC_VS_FORMAT_MJPEG: - info->format.bDescriptorSubtype = block[2]; - info->format.bFormatIndex = block[3]; - memcpy(info->format.fourccFormat, "MJPG", 4); - info->format.bmFlags = block[5]; - info->format.bBitsPerPixel = 0; - info->format.bDefaultFrameIndex = block[6]; - info->format.bAspectRatioX = block[7]; - info->format.bAspectRatioY = block[8]; - info->format.bmInterlaceFlags = block[9]; - info->format.bCopyProtect = block[10]; - break; - case UVC_VS_FRAME_UNCOMPRESSED: - case UVC_VS_FRAME_MJPEG: - info->frame.bDescriptorSubtype = block[2]; - info->frame.bFrameIndex = block[3]; - info->frame.bmCapabilities = block[4]; - info->frame.wWidth = block[5] + (block[6] << 8); - info->frame.wHeight = block[7] + (block[8] << 8); - info->frame.dwMinBitRate = DW_TO_INT(&block[9]); - info->frame.dwMaxBitRate = DW_TO_INT(&block[13]); - info->frame.dwMaxVideoFrameBufferSize = DW_TO_INT(&block[17]); - info->frame.dwDefaultFrameInterval = DW_TO_INT(&block[21]); - info->frame.bFrameIntervalType = block[25]; - - if (block[25] == 0) { - info->frame.dwMinFrameInterval = DW_TO_INT(&block[26]); - info->frame.dwMaxFrameInterval = DW_TO_INT(&block[30]); - info->frame.dwFrameIntervalStep = DW_TO_INT(&block[34]); - } else { - info->frame.intervals = calloc(block[25] + 1, sizeof(info->frame.intervals[0])); - p = &block[26]; - for (i = 0; i < block[25]; ++i) { - info->frame.intervals[i] = DW_TO_INT(p); - p += 4; - } - info->frame.intervals[block[25]] = 0; - } - break; - case UVC_VS_FORMAT_MPEG2TS: - printf("unsupported descriptor subtype VS_FORMAT_MPEG2TS\n"); - break; - case UVC_VS_FORMAT_DV: - printf("unsupported descriptor subtype VS_FORMAT_DV\n"); - break; - case UVC_VS_COLORFORMAT: - printf("unsupported descriptor subtype VS_COLORFORMAT\n"); - break; - case UVC_VS_FORMAT_FRAME_BASED: - info->format.bDescriptorSubtype = block[2]; - info->format.bFormatIndex = block[3]; - info->format.bNumFrameDescriptors = block[4]; - memcpy(info->format.guidFormat, &block[5], 16); - info->format.bBitsPerPixel = block[21]; - info->format.bDefaultFrameIndex = block[22]; - info->format.bAspectRatioX = block[23]; - info->format.bAspectRatioY = block[24]; - info->format.bmInterlaceFlags = block[25]; - info->format.bCopyProtect = block[26]; - info->format.bVariableSize = block[27]; - break; - case UVC_VS_FRAME_FRAME_BASED: - info->frame.bDescriptorSubtype = block[2]; - info->frame.bFrameIndex = block[3]; - info->frame.bmCapabilities = block[4]; - info->frame.wWidth = block[5] + (block[6] << 8); - info->frame.wHeight = block[7] + (block[8] << 8); - info->frame.dwMinBitRate = DW_TO_INT(&block[9]); - info->frame.dwMaxBitRate = DW_TO_INT(&block[13]); - info->frame.dwDefaultFrameInterval = DW_TO_INT(&block[17]); - info->frame.bFrameIntervalType = block[21]; - info->frame.dwBytesPerLine = DW_TO_INT(&block[22]); - if (block[21] == 0) { - info->frame.dwMinFrameInterval = DW_TO_INT(&block[26]); - info->frame.dwMaxFrameInterval = DW_TO_INT(&block[30]); - info->frame.dwFrameIntervalStep = DW_TO_INT(&block[34]); - } else { - info->frame.intervals = calloc(block[21] + 1, sizeof(info->frame.intervals[0])); - p = &block[26]; - for (i = 0; i < block[21]; ++i) { - info->frame.intervals[i] = DW_TO_INT(p); - p += 4; - } - info->frame.intervals[block[21]] = 0; - } - break; - case UVC_VS_FORMAT_STREAM_BASED: - printf("unsupported descriptor subtype VS_FORMAT_STREAM_BASED\n"); - break; - default: - /** @todo handle JPEG and maybe still frames or even DV... */ - printf("unsupported descriptor subtype: %d\n", descriptor_subtype); - break; - } - - return ret; -} - -static int ucam_scan_streaming(struct ucam_ctx *c, struct ucam_dev_info *info, - int if_idx) -{ - const struct libusb_interface_descriptor *if_desc; - const unsigned char *buffer; - size_t buffer_left, block_size; - int ret, parse_ret; - - ret = 0; - - if_desc = &(info->usb_conf->interface[if_idx].altsetting[0]); - buffer = if_desc->extra; - buffer_left = if_desc->extra_length; - - info->stream.bInterfaceNumber = if_desc->bInterfaceNumber; - - while (buffer_left >= 3) { - block_size = buffer[0]; - parse_ret = ucam_parse_vs(c, info, &info->stream, buffer, block_size); - if (parse_ret != 0) { - ret = parse_ret; - break; - } - - buffer_left -= block_size; - buffer += block_size; - } - - return ret; -} - -static int ucam_parse_vc_header(struct ucam_ctx *c, struct ucam_dev_info *info, - const unsigned char *block, size_t block_size) -{ - size_t i; - int scan_ret, ret = 0; - - /* - int uvc_version; - uvc_version = (block[4] >> 4) * 1000 + (block[4] & 0x0f) * 100 - + (block[3] >> 4) * 10 + (block[3] & 0x0f); - */ - info->control.bcdUVC = SW_TO_SHORT(&block[3]); - - switch (info->control.bcdUVC) { - case 0x0100: - info->control.dwClockFrequency = DW_TO_INT(block + 7); - break; - case 0x010a: - info->control.dwClockFrequency = DW_TO_INT(block + 7); - break; - case 0x0110: - break; - default: - break; - } - - for (i = 12; i < block_size; ++i) { - scan_ret = ucam_scan_streaming(c, info, block[i]); - if (scan_ret != 0) { - ret = scan_ret; - break; - } - } - - return ret; -} - -static int ucam_parse_vc_input_terminal(struct ucam_ctx *c, - struct ucam_dev_info *info, - const unsigned char *block, size_t block_size) -{ - size_t i; - - /* only supporting camera-type input terminals */ - if (SW_TO_SHORT(&block[4]) != UVC_ITT_CAMERA) { - printf("only support camera-type input terminals\n"); - return -1; - } - - info->control.term.bTerminalID = block[3]; - info->control.term.wTerminalType = SW_TO_SHORT(&block[4]); - info->control.term.wObjectiveFocalLengthMin = SW_TO_SHORT(&block[8]); - info->control.term.wObjectiveFocalLengthMax = SW_TO_SHORT(&block[10]); - info->control.term.wOcularFocalLength = SW_TO_SHORT(&block[12]); - - for (i = 14 + block[14]; i >= 15; --i) - info->control.term.bmControls = block[i] + (info->control.term.bmControls << 8); - - return 0; -} - -static int ucam_get_dev_list(struct ucam_ctx *c) -{ - struct libusb_device **dev_list; - struct libusb_device *pdev; - struct libusb_config_descriptor *conf; - struct libusb_device_descriptor desc; - const struct libusb_interface *intf; - const struct libusb_interface_descriptor *if_desc; - uint8_t got_dev; - int alt_idx; - int num_uvc_devices; - int dev_idx; - int if_idx; - - int num_usb_devices = libusb_get_device_list(c->usb_ctx, &dev_list); - if (num_usb_devices < 0) { - printf("libusb_get_device_list failed!\n"); - return -1; - } - - num_uvc_devices = 0; - dev_idx = -1; - - while ((pdev = dev_list[++dev_idx]) != NULL) { - got_dev = 0; - if (libusb_get_config_descriptor(pdev, 0, &conf) != 0) - continue; - - if (libusb_get_device_descriptor(pdev, &desc) != LIBUSB_SUCCESS) - continue; - - for (if_idx = 0; !got_dev && if_idx < conf->bNumInterfaces; - ++if_idx) { - intf = &conf->interface[if_idx]; - - for (alt_idx = 0; !got_dev && alt_idx < intf->num_altsetting; - ++alt_idx) { - if_desc = &intf->altsetting[alt_idx]; - - // Skip TIS cameras that definitely aren't UVC even though they might - // look that way - if (0x199e == desc.idVendor && - desc.idProduct >= 0x8201 && desc.idProduct <= 0x8208) { - continue; - } - - // Special case for Imaging Source cameras - /* Video, Streaming */ - if (0x199e == desc.idVendor && - (0x8101 == desc.idProduct || 0x8102 == desc.idProduct) && - if_desc->bInterfaceClass == 255 && - if_desc->bInterfaceSubClass == 2 ) { - got_dev = 1; - printf("got special usb device 0x%x, 0x%x\n", - desc.idVendor, desc.idProduct); - } - - /* Video, Streaming */ - if (if_desc->bInterfaceClass == 14 && - if_desc->bInterfaceSubClass == 2) { - got_dev = 1; - printf("got usb device 0x%x, 0x%x\n", - desc.idVendor, desc.idProduct); - } - } - } - - libusb_free_config_descriptor(conf); - - if (got_dev) { - num_uvc_devices++; - c->usb_dev = pdev; - break; - } - } - - libusb_free_device_list(dev_list, 1); - printf("find %d uvc devices\n", num_uvc_devices); - if (!got_dev) - return -1; - return 0; -} - -static int ucam_get_dev_desc(struct ucam_ctx *c, struct ucam_dev_info *info) -{ - unsigned char buf[64]; - struct libusb_device_descriptor usb_desc; - if (libusb_get_device_descriptor(c->usb_dev, &usb_desc) != 0) { - printf("libusb_get_device_descriptor failed!\n"); - return -1; - } - info->descriptor.idVendor = usb_desc.idVendor; - info->descriptor.idProduct = usb_desc.idProduct; - - if (libusb_open(c->usb_dev, &c->usb_devh) != 0) { - printf("libusb_open device %04x:%04x failed!\n", - usb_desc.idVendor, usb_desc.idProduct); - return -1; - } - - if (libusb_get_string_descriptor_ascii(c->usb_devh, usb_desc.iSerialNumber, - buf, sizeof(buf)) > 0) { - info->descriptor.serialNumber = strdup((const char*) buf); - printf("serialNumber %s\n", info->descriptor.serialNumber); - } - - if (libusb_get_string_descriptor_ascii(c->usb_devh, usb_desc.iManufacturer, - buf, sizeof(buf)) > 0) { - info->descriptor.manufacturer = strdup((const char*) buf); - printf("manufacturer %s\n", info->descriptor.manufacturer); - } - - if (libusb_get_string_descriptor_ascii(c->usb_devh, usb_desc.iProduct, - buf, sizeof(buf)) > 0) { - info->descriptor.product = strdup((const char*) buf); - printf("product %s\n", info->descriptor.product); - } - - libusb_close(c->usb_devh); - return 0; -} - -static int ucam_claim_if(struct ucam_ctx *c, int idx) -{ - int ret = 0; - - /* Tell libusb to detach any active kernel drivers. libusb will keep track of whether - * it found a kernel driver for this interface. */ - ret = libusb_detach_kernel_driver(c->usb_devh, idx); - if (ret == 0 || ret == LIBUSB_ERROR_NOT_FOUND || - ret == LIBUSB_ERROR_NOT_SUPPORTED) { - if (libusb_claim_interface(c->usb_devh, idx) != 0) { - printf("libusb_claim_interface failed!"); - } - } else { - printf("not claiming interface %d: unable to detach kernel driver (%s)\n", - idx, libusb_strerror(ret)); - } - printf("ucam_claim_if %s\n", libusb_strerror(ret)); - - return 0; -} - -static int ucam_parse_vc(struct ucam_ctx *c, struct ucam_dev_info *info, - const unsigned char *block, size_t block_size) -{ - int descriptor_subtype; - int ret = 0; - int i; - - if (block[1] != 36) { // not a CS_INTERFACE descriptor?? - printf("ucam_parse_vc invalid!\n"); - return -1; - } - - descriptor_subtype = block[2]; - switch (descriptor_subtype) { - case UVC_VC_HEADER: - ret = ucam_parse_vc_header(c, info, block, block_size); - break; - case UVC_VC_INPUT_TERMINAL: - ret = ucam_parse_vc_input_terminal(c, info, block, block_size); - break; - case UVC_VC_OUTPUT_TERMINAL: - break; - case UVC_VC_SELECTOR_UNIT: - info->control.selector.bUnitID = block[3]; - break; - case UVC_VC_PROCESSING_UNIT: - info->control.processing.bUnitID = block[3]; - info->control.processing.bSourceID = block[4]; - for (i = 7 + block[7]; i >= 8; --i) - info->control.processing.bmControls = block[i] + (info->control.processing.bmControls << 8); - break; - case UVC_VC_EXTENSION_UNIT: { - const uint8_t *start_of_controls; - int size_of_controls, num_in_pins; - info->control.extension.bUnitID = block[3]; - memcpy(info->control.extension.guidExtensionCode, &block[4], 16); - num_in_pins = block[21]; - size_of_controls = block[22 + num_in_pins]; - start_of_controls = &block[23 + num_in_pins]; - for (i = size_of_controls - 1; i >= 0; --i) - info->control.extension.bmControls = start_of_controls[i] + (info->control.extension.bmControls << 8); - } break; - default: - ret = -1; - break; - } - - return ret; -} - -static int ucam_get_devinfo(struct ucam_ctx *c, struct ucam_dev_info *info) -{ - int ret = 0; - int is_TISCamera = 0; - int if_idx; - size_t buffer_left, block_size; - const unsigned char *buffer; - const struct libusb_interface_descriptor *if_desc; - - if (libusb_get_config_descriptor(c->usb_dev, 0, &info->usb_conf) != 0) { - printf("libusb_get_config_descriptor failed!\n"); - return -1; - } - - if (ucam_get_dev_desc(c, info) != 0) { - printf("ucam_get_dev_desc failed!\n"); - return -1; - } - printf("got usb device 0x%x, 0x%x, %s\n", - info->descriptor.idVendor, info->descriptor.idProduct, info->descriptor.serialNumber); - - if (0x199e == info->descriptor.idVendor && - (0x8101 == info->descriptor.idProduct || - 0x8102 == info->descriptor.idProduct )) { - is_TISCamera = 1; - } - - for (if_idx = 0; if_idx < info->usb_conf->bNumInterfaces; ++if_idx) { - if_desc = &info->usb_conf->interface[if_idx].altsetting[0]; - if (is_TISCamera && - if_desc->bInterfaceClass == 255 && - if_desc->bInterfaceSubClass == 1) // Video, Control - break; - if (if_desc->bInterfaceClass == 14 && - if_desc->bInterfaceSubClass == 1) // Video, Control - break; - if_desc = NULL; - } - - if (if_desc == NULL) { - printf("not found interface!\n"); - return -1; - } - - info->control.bInterfaceNumber = if_idx; - if (if_desc->bNumEndpoints != 0) { - info->control.bEndpointAddress = if_desc->endpoint[0].bEndpointAddress; - } - - buffer = if_desc->extra; - buffer_left = if_desc->extra_length; - block_size = 0; - block_size = block_size; - - while (buffer_left >= 3) { // parseX needs to see buf[0,2] = length,type - block_size = buffer[0]; - if (ucam_parse_vc(c, info, buffer, block_size) != 0) { - ret = -1; - break; - } - - buffer_left -= block_size; - buffer += block_size; - } - - return ret; -} - -static int ucam_find_device(struct ucam_ctx *c) -{ - if (ucam_get_dev_list(c) != 0) { - printf("ucam_get_dev_list failed!\n"); - return -1; - } - - if (ucam_get_devinfo(c, &c->dev_info) != 0) { - printf("ucam_get_devinfo failed!\n"); - return -1; - } - return 0; -} - -static void ucam_process_control_status(struct ucam_ctx *c, unsigned char *data, int len) -{ - enum uvc_status_class status_class; - uint8_t originator = 0, selector = 0, event = 0; - enum uvc_status_attribute attribute = UVC_STATUS_ATTRIBUTE_UNKNOWN; - void *content = NULL; - size_t content_len = 0; - int found_entity = 0; - - if (len < 5) { - printf("Short read of VideoControl status update (%d bytes)", len); - return; - } - - originator = data[1]; - event = data[2]; - selector = data[3]; - - if (originator == 0) { - printf("Unhandled update from VC interface"); - return; /* @todo VideoControl virtual entity interface updates */ - } - - if (event != 0) { - printf("Unhandled VC event %d", (int) event); - return; - } - - /* printf("bSelector: %d\n", selector); */ - if (c->dev_info.control.term.bTerminalID == originator) { - status_class = UVC_STATUS_CLASS_CONTROL_CAMERA; - found_entity = 1; - } - - if (!found_entity) { - if (c->dev_info.control.processing.bUnitID == originator) { - status_class = UVC_STATUS_CLASS_CONTROL_PROCESSING; - found_entity = 1; - } - } - - if (!found_entity) { - printf("Got status update for unknown VideoControl entity %d", - (int) originator); - return; - } - - attribute = data[4]; - content = data + 5; - content_len = len - 5; - - printf("Event: class=%d, event=%d, selector=%d, attribute=%d, content_len=%zd", - status_class, event, selector, attribute, content_len); - - if (c->status_cb) { - printf("Running user-supplied status callback"); - c->status_cb(status_class, - event, - selector, - attribute, - content, content_len, - c->status_user_ptr); - } -} - -static void ucam_process_streaming_status(struct ucam_ctx *c, unsigned char *data, int len) -{ - if (len < 3) { - printf("Invalid streaming status event received.\n"); - return; - } - - if (data[2] == 0) { - if (len < 4) { - printf("Short read of status update (%d bytes)", len); - return; - } - printf("Button (intf %u) %s len %d\n", data[1], data[3] ? "pressed" : "released", len); - if (c->button_cb) { - printf("Running user-supplied button callback"); - c->button_cb(data[1], - data[3], - c->button_user_ptr); - } - } else { - printf("Stream %u error event %02x %02x len %d.\n", data[1], data[2], data[3], len); - } -} - -void ucam_process_status_xfer(struct ucam_ctx *c, - struct libusb_transfer *transfer) -{ - /* printf("Got transfer of aLen = %d\n", transfer->actual_length); */ - if (transfer->actual_length > 0) { - switch (transfer->buffer[0] & 0x0f) { - case 1: /* VideoControl interface */ - ucam_process_control_status(c, transfer->buffer, transfer->actual_length); - break; - case 2: /* VideoStreaming interface */ - ucam_process_streaming_status(c, transfer->buffer, transfer->actual_length); - break; - } - } -} - -static void _ucam_status_callback(struct libusb_transfer *transfer) -{ - struct ucam_ctx *c = (struct ucam_ctx *)transfer->user_data; - switch (transfer->status) { - case LIBUSB_TRANSFER_ERROR: - case LIBUSB_TRANSFER_CANCELLED: - case LIBUSB_TRANSFER_NO_DEVICE: - printf("not processing/resubmitting, status = %d", transfer->status); - return; - case LIBUSB_TRANSFER_COMPLETED: - ucam_process_status_xfer(c, transfer); - break; - case LIBUSB_TRANSFER_TIMED_OUT: - case LIBUSB_TRANSFER_STALL: - case LIBUSB_TRANSFER_OVERFLOW: - printf("retrying transfer, status = %d", transfer->status); - break; - } - libusb_submit_transfer(transfer); -} - -static const char *_uvc_name_for_format_subtype(uint8_t subtype) -{ - switch (subtype) { - case UVC_VS_FORMAT_UNCOMPRESSED: - return "UncompressedFormat"; - case UVC_VS_FORMAT_MJPEG: - return "MJPEGFormat"; - case UVC_VS_FORMAT_FRAME_BASED: - return "FrameFormat"; - default: - return "Unknown"; - } -} - -static int ucam_print_info(struct ucam_ctx *c) -{ - struct ucam_ctrl *ctrl = &c->dev_info.control; - struct ucam_descriptor *desc = &c->dev_info.descriptor; - struct ucam_stream *stream = &c->dev_info.stream; - struct ucam_frame_desc *frame = &c->dev_info.frame; - struct ucam_format_desc *format = &c->dev_info.format; - int stream_idx = 0; - - if (!ctrl->bcdUVC) { - printf("usb bcdUVC is invalid!\n"); - return -1; - } - - printf("DEVICE CONFIGURATION (%04x:%04x/%s) ---\n", - desc->idVendor, desc->idProduct, - desc->serialNumber ? desc->serialNumber : "[none]"); - - printf("Status: %s\n", stream ? "streaming" : "idle"); - printf("VideoControl:\n" - "\tbcdUVC: 0x%04x\n", - ctrl->bcdUVC); - - ++stream_idx; - - printf("VideoStreaming(%d):\n" - "\tbEndpointAddress: %d\n\tFormats:\n", - stream_idx, stream->bEndpointAddress); - - int i; - - switch (format->bDescriptorSubtype) { - case UVC_VS_FORMAT_UNCOMPRESSED: - case UVC_VS_FORMAT_MJPEG: - case UVC_VS_FORMAT_FRAME_BASED: - printf("\t\%s(%d)\n" - "\t\t bits per pixel: %d\n" - "\t\t GUID: ", - _uvc_name_for_format_subtype(format->bDescriptorSubtype), - format->bFormatIndex, - format->bBitsPerPixel); - - for (i = 0; i < 16; ++i) - printf("%02x", format->guidFormat[i]); - - printf(" (%4s)\n", format->fourccFormat); - - printf("\t\t default frame: %d\n" - "\t\t aspect ratio: %dx%d\n" - "\t\t interlace flags: %02x\n" - "\t\t copy protect: %02x\n", - format->bDefaultFrameIndex, - format->bAspectRatioX, - format->bAspectRatioY, - format->bmInterlaceFlags, - format->bCopyProtect); - - printf("\t\t\tFrameDescriptor(%d)\n" - "\t\t\t capabilities: %02x\n" - "\t\t\t size: %dx%d\n" - "\t\t\t bit rate: %d-%d\n" - "\t\t\t max frame size: %d\n" - "\t\t\t default interval: 1/%d\n", - frame->bFrameIndex, - frame->bmCapabilities, - frame->wWidth, - frame->wHeight, - frame->dwMinBitRate, - frame->dwMaxBitRate, - frame->dwMaxVideoFrameBufferSize, - 10000000 / frame->dwDefaultFrameInterval); - if (frame->intervals) { - uint32_t *ptr; - for (ptr = frame->intervals; *ptr; ++ptr) { - printf("\t\t\t interval[%d]: 1/%d\n", - (int) (ptr - frame->intervals), - 10000000 / *ptr); - } - } else { - printf("\t\t\t min interval[%d] = 1/%d\n" - "\t\t\t max interval[%d] = 1/%d\n", - frame->dwMinFrameInterval, - 10000000 / frame->dwMinFrameInterval, - frame->dwMaxFrameInterval, - 10000000 / frame->dwMaxFrameInterval); - if (frame->dwFrameIntervalStep) - printf("\t\t\t interval step[%d] = 1/%d\n", - frame->dwFrameIntervalStep, - 10000000 / frame->dwFrameIntervalStep); - } - break; - default: - printf("\t-UnknownFormat (%d)\n", - format->bDescriptorSubtype); - } - return 0; -} - -struct format_table_entry { - enum uvc_frame_format format; - uint8_t abstract_fmt; - uint8_t guid[16]; - int children_count; - enum uvc_frame_format *children; -}; - -struct format_table_entry *_get_format_entry(enum uvc_frame_format format) -{ - #define ABS_FMT(_fmt, _num, ...) \ - case _fmt: { \ - static enum uvc_frame_format _fmt##_children[] = __VA_ARGS__; \ - static struct format_table_entry _fmt##_entry = { \ - _fmt, 0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, _num, _fmt##_children }; \ - return &_fmt##_entry; } - - #define FMT(_fmt, ...) \ - case _fmt: { \ - static struct format_table_entry _fmt##_entry = { \ - _fmt, 0, __VA_ARGS__, 0, NULL }; \ - return &_fmt##_entry; } - - switch(format) { - /* Define new formats here */ - ABS_FMT(UVC_FRAME_FORMAT_ANY, 2, - {UVC_FRAME_FORMAT_UNCOMPRESSED, UVC_FRAME_FORMAT_COMPRESSED}) - - ABS_FMT(UVC_FRAME_FORMAT_UNCOMPRESSED, 3, - {UVC_FRAME_FORMAT_YUYV, UVC_FRAME_FORMAT_UYVY, UVC_FRAME_FORMAT_GRAY8}) - FMT(UVC_FRAME_FORMAT_YUYV, - {'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}) - FMT(UVC_FRAME_FORMAT_UYVY, - {'U', 'Y', 'V', 'Y', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}) - FMT(UVC_FRAME_FORMAT_GRAY8, - {'Y', '8', '0', '0', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}) - FMT(UVC_FRAME_FORMAT_BY8, - {'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}) - - ABS_FMT(UVC_FRAME_FORMAT_COMPRESSED, 1, - {UVC_FRAME_FORMAT_MJPEG}) - FMT(UVC_FRAME_FORMAT_MJPEG, - {'M', 'J', 'P', 'G'}) - default: - return NULL; - } - - #undef ABS_FMT - #undef FMT -} - -uint8_t _uvc_frame_format_matches_guid(enum uvc_frame_format fmt, uint8_t guid[16]) -{ - struct format_table_entry *format; - int child_idx; - - format = _get_format_entry(fmt); - if (!format) - return 0; - - if (!format->abstract_fmt && !memcmp(guid, format->guid, 16)) - return 1; - - for (child_idx = 0; child_idx < format->children_count; child_idx++) { - if (_uvc_frame_format_matches_guid(format->children[child_idx], guid)) - return 1; - } - - return 0; -} - -static int uvc_get_stream_ctrl_format_size( - struct ucam_ctx *c, - struct ucam_stream_ctrl *ctrl, - enum uvc_frame_format cf, - int width, int height, - int fps) -{ -#if 0 - uvc_streaming_interface_t *stream_if; - - /* find a matching frame descriptor and interval */ - DL_FOREACH(devh->info->stream_ifs, stream_if) { - uvc_format_desc_t *format; - - DL_FOREACH(stream_if->format_descs, format) { - uvc_frame_desc_t *frame; - - if (!_uvc_frame_format_matches_guid(cf, format->guidFormat)) - continue; - - DL_FOREACH(format->frame_descs, frame) { - if (frame->wWidth != width || frame->wHeight != height) - continue; - - uint32_t *interval; - - if (frame->intervals) { - for (interval = frame->intervals; *interval; ++interval) { - // allow a fps rate of zero to mean "accept first rate available" - if (10000000 / *interval == (unsigned int) fps || fps == 0) { - - /* get the max values -- we need the interface number to be able - to do this */ - ctrl->bInterfaceNumber = stream_if->bInterfaceNumber; - uvc_query_stream_ctrl( devh, ctrl, 1, UVC_GET_MAX); - - ctrl->bmHint = (1 << 0); /* don't negotiate interval */ - ctrl->bFormatIndex = format->bFormatIndex; - ctrl->bFrameIndex = frame->bFrameIndex; - ctrl->dwFrameInterval = *interval; - - goto found; - } - } - } else { - uint32_t interval_100ns = 10000000 / fps; - uint32_t interval_offset = interval_100ns - frame->dwMinFrameInterval; - - if (interval_100ns >= frame->dwMinFrameInterval - && interval_100ns <= frame->dwMaxFrameInterval - && !(interval_offset - && (interval_offset % frame->dwFrameIntervalStep))) { - - /* get the max values -- we need the interface number to be able - to do this */ - ctrl->bInterfaceNumber = stream_if->bInterfaceNumber; - uvc_query_stream_ctrl( devh, ctrl, 1, UVC_GET_MAX); - - ctrl->bmHint = (1 << 0); - ctrl->bFormatIndex = format->bFormatIndex; - ctrl->bFrameIndex = frame->bFrameIndex; - ctrl->dwFrameInterval = interval_100ns; - - goto found; - } - } - } - } - } - - return UVC_ERROR_INVALID_MODE; - -found: - return uvc_probe_stream_ctrl(devh, ctrl); -#endif - return 0; -} -static void *ucam_handle_events(void *arg) -{ - struct ucam_ctx *c = (struct ucam_ctx *)arg; - - while (c->thread_run) - libusb_handle_events_completed(c->usb_ctx, &c->thread_run); - return NULL; -} - -static void *ucam_open(struct uvc_ctx *uvc, const char *dev, struct uvc_config *conf) -{ - int ret; - struct ucam_ctx *c = calloc(1, sizeof(struct ucam_ctx)); - if (!c) { - printf("malloc ucam_ctx failed!\n"); - return NULL; - } - if (libusb_init(&c->usb_ctx) < 0) { - printf("libusb_init failed!\n"); - return NULL; - } - libusb_set_debug(c->usb_ctx, LIBUSB_LOG_LEVEL_INFO); - - if (ucam_find_device(c) < 0) { - printf("ucam_find_device failed!\n"); - return NULL; - } - ucam_print_info(c); - - ret = libusb_open(c->usb_dev, &c->usb_devh); - if (ret < 0) { - printf("libusb_open failed %s!\n", libusb_strerror(ret)); - return NULL; - } - //libusb_ref_device(c->usb_dev); - - - if (ucam_claim_if(c, c->dev_info.control.bInterfaceNumber) != 0) { - printf("ucam_claim_if failed!\n"); - return NULL; - } - - if (c->dev_info.control.bEndpointAddress) { - c->usb_xfer = libusb_alloc_transfer(0); - if (!c->usb_xfer) { - ret = -1; - printf("libusb_alloc_transfer failed!\n"); - return NULL; - } - - libusb_fill_interrupt_transfer(c->usb_xfer, - c->usb_devh, - c->dev_info.control.bEndpointAddress, - c->status_buf, - sizeof(c->status_buf), - _ucam_status_callback, - c, - 0); - ret = libusb_submit_transfer(c->usb_xfer); - if (ret) { - printf("libusb_submit_transfer failed: %s\n", libusb_strerror(ret)); - return NULL; - } - printf("libusb_submit_transfer: %s\n", libusb_strerror(ret)); - } - c->thread_run = 1; - pthread_create(&c->tid, NULL, ucam_handle_events, c); - - uvc->opaque = c; - printf("ucam_open ok!\n"); - return c; -} - -static void ucam_close(struct uvc_ctx *uvc) -{ - struct ucam_ctx *c = (struct ucam_ctx *)uvc->opaque; - libusb_exit(c->usb_ctx); - free(c); -} - -static int ucam_stream_open_ctrl(struct ucam_ctx *c, - struct ucam_stream_handle **strmhp, - struct ucam_stream_ctrl *ctrl) -{ -#if 0 - /* Chosen frame and format descriptors */ - uvc_stream_handle_t *strmh = NULL; - uvc_streaming_interface_t *stream_if; - uvc_error_t ret; - - UVC_ENTER(); - - if (_uvc_get_stream_by_interface(devh, ctrl->bInterfaceNumber) != NULL) { - ret = UVC_ERROR_BUSY; /* Stream is already opened */ - goto fail; - } - - stream_if = _uvc_get_stream_if(devh, ctrl->bInterfaceNumber); - if (!stream_if) { - ret = UVC_ERROR_INVALID_PARAM; - goto fail; - } - - strmh = calloc(1, sizeof(*strmh)); - if (!strmh) { - ret = UVC_ERROR_NO_MEM; - goto fail; - } - strmh->devh = devh; - strmh->stream_if = stream_if; - strmh->frame.library_owns_data = 1; - - ret = uvc_claim_if(strmh->devh, strmh->stream_if->bInterfaceNumber); - if (ret != UVC_SUCCESS) - goto fail; - - ret = uvc_stream_ctrl(strmh, ctrl); - if (ret != UVC_SUCCESS) - goto fail; - - // Set up the streaming status and data space - strmh->running = 0; - /** @todo take only what we need */ - strmh->outbuf = malloc( LIBUVC_XFER_BUF_SIZE ); - strmh->holdbuf = malloc( LIBUVC_XFER_BUF_SIZE ); - - pthread_mutex_init(&strmh->cb_mutex, NULL); - pthread_cond_init(&strmh->cb_cond, NULL); - - DL_APPEND(devh->streams, strmh); - - *strmhp = strmh; - - UVC_EXIT(0); - return UVC_SUCCESS; - -fail: - if(strmh) - free(strmh); - UVC_EXIT(ret); - return ret; -#endif - return 0; -} - -static int ucam_start_stream(struct uvc_ctx *uvc) -{ - int ret; - struct ucam_ctx *c = (struct ucam_ctx *)uvc->opaque; - - uvc_get_stream_ctrl_format_size(c, &c->dev_info.stream_ctrl, - UVC_FRAME_FORMAT_YUYV, 640, 480, 30); - - ret = ucam_stream_open_ctrl(c, &c->strmh, &c->dev_info.stream_ctrl); - if (ret != 0) - return ret; - -#if 0 - ret = ucam_stream_start(strmh, cb, user_ptr, flags); - if (ret != 0) { - ucam_stream_close(strmh); - return ret; - } -#endif - - return 0; -} - -static int ucam_stop_stream(struct uvc_ctx *uvc) -{ - return 0; -} - -static int ucam_query_frame(struct uvc_ctx *uvc, struct video_frame *frame) -{ - return 0; -} - -static int ucam_ioctl(struct uvc_ctx *uvc, unsigned long int cmd, ...) -{ - return 0; -} - -struct uvc_ops ucam_ops = { - ._open = ucam_open, - ._close = ucam_close, - .ioctl = ucam_ioctl, - .start_stream = ucam_start_stream, - .stop_stream = ucam_stop_stream, - .query_frame = ucam_query_frame, -}; diff --git a/gear-lib/libuvc/usbcam.h b/gear-lib/libuvc/usbcam.h deleted file mode 100644 index f5b5589..0000000 --- a/gear-lib/libuvc/usbcam.h +++ /dev/null @@ -1,458 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2014-2020 Zhifeng Gong - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - ******************************************************************************/ -#ifndef USBCAM_H -#define USBCAM_H -/* - * refer to https://github.com/libuvc/libuvc - */ - -/** Converts an unaligned four-byte little-endian integer into an int32 */ -#define DW_TO_INT(p) ((p)[0] | ((p)[1] << 8) | ((p)[2] << 16) | ((p)[3] << 24)) -/** Converts an unaligned two-byte little-endian integer into an int16 */ -#define SW_TO_SHORT(p) ((p)[0] | ((p)[1] << 8)) -/** Converts an int16 into an unaligned two-byte little-endian integer */ -#define SHORT_TO_SW(s, p) \ - (p)[0] = (s); \ - (p)[1] = (s) >> 8; -/** Converts an int32 into an unaligned four-byte little-endian integer */ -#define INT_TO_DW(i, p) \ - (p)[0] = (i); \ - (p)[1] = (i) >> 8; \ - (p)[2] = (i) >> 16; \ - (p)[3] = (i) >> 24; - -/** VideoControl interface descriptor subtype (A.5) */ -enum uvc_vc_desc_subtype { - UVC_VC_DESCRIPTOR_UNDEFINED = 0x00, - UVC_VC_HEADER = 0x01, - UVC_VC_INPUT_TERMINAL = 0x02, - UVC_VC_OUTPUT_TERMINAL = 0x03, - UVC_VC_SELECTOR_UNIT = 0x04, - UVC_VC_PROCESSING_UNIT = 0x05, - UVC_VC_EXTENSION_UNIT = 0x06 -}; - -/** VideoStreaming interface descriptor subtype (A.6) */ -enum uvc_vs_desc_subtype { - UVC_VS_UNDEFINED = 0x00, - UVC_VS_INPUT_HEADER = 0x01, - UVC_VS_OUTPUT_HEADER = 0x02, - UVC_VS_STILL_IMAGE_FRAME = 0x03, - UVC_VS_FORMAT_UNCOMPRESSED = 0x04, - UVC_VS_FRAME_UNCOMPRESSED = 0x05, - UVC_VS_FORMAT_MJPEG = 0x06, - UVC_VS_FRAME_MJPEG = 0x07, - UVC_VS_FORMAT_MPEG2TS = 0x0a, - UVC_VS_FORMAT_DV = 0x0c, - UVC_VS_COLORFORMAT = 0x0d, - UVC_VS_FORMAT_FRAME_BASED = 0x10, - UVC_VS_FRAME_FRAME_BASED = 0x11, - UVC_VS_FORMAT_STREAM_BASED = 0x12 -}; - -/** UVC endpoint descriptor subtype (A.7) */ -enum uvc_ep_desc_subtype { - UVC_EP_UNDEFINED = 0x00, - UVC_EP_GENERAL = 0x01, - UVC_EP_ENDPOINT = 0x02, - UVC_EP_INTERRUPT = 0x03 -}; - -/** VideoControl interface control selector (A.9.1) */ -enum uvc_vc_ctrl_selector { - UVC_VC_CONTROL_UNDEFINED = 0x00, - UVC_VC_VIDEO_POWER_MODE_CONTROL = 0x01, - UVC_VC_REQUEST_ERROR_CODE_CONTROL = 0x02 -}; - -/** Terminal control selector (A.9.2) */ -enum uvc_term_ctrl_selector { - UVC_TE_CONTROL_UNDEFINED = 0x00 -}; - -/** Selector unit control selector (A.9.3) */ -enum uvc_su_ctrl_selector { - UVC_SU_CONTROL_UNDEFINED = 0x00, - UVC_SU_INPUT_SELECT_CONTROL = 0x01 -}; - -/** Extension unit control selector (A.9.6) */ -enum uvc_xu_ctrl_selector { - UVC_XU_CONTROL_UNDEFINED = 0x00 -}; - -/** VideoStreaming interface control selector (A.9.7) */ -enum uvc_vs_ctrl_selector { - UVC_VS_CONTROL_UNDEFINED = 0x00, - UVC_VS_PROBE_CONTROL = 0x01, - UVC_VS_COMMIT_CONTROL = 0x02, - UVC_VS_STILL_PROBE_CONTROL = 0x03, - UVC_VS_STILL_COMMIT_CONTROL = 0x04, - UVC_VS_STILL_IMAGE_TRIGGER_CONTROL = 0x05, - UVC_VS_STREAM_ERROR_CODE_CONTROL = 0x06, - UVC_VS_GENERATE_KEY_FRAME_CONTROL = 0x07, - UVC_VS_UPDATE_FRAME_SEGMENT_CONTROL = 0x08, - UVC_VS_SYNC_DELAY_CONTROL = 0x09 -}; - -/** USB terminal type (B.1) */ -enum uvc_term_type { - UVC_TT_VENDOR_SPECIFIC = 0x0100, - UVC_TT_STREAMING = 0x0101 -}; - -/** Input terminal type (B.2) */ -enum uvc_it_type { - UVC_ITT_VENDOR_SPECIFIC = 0x0200, - UVC_ITT_CAMERA = 0x0201, - UVC_ITT_MEDIA_TRANSPORT_INPUT = 0x0202 -}; - -/** Output terminal type (B.3) */ -enum uvc_ot_type { - UVC_OTT_VENDOR_SPECIFIC = 0x0300, - UVC_OTT_DISPLAY = 0x0301, - UVC_OTT_MEDIA_TRANSPORT_OUTPUT = 0x0302 -}; - -/** External terminal type (B.4) */ -enum uvc_et_type { - UVC_EXTERNAL_VENDOR_SPECIFIC = 0x0400, - UVC_COMPOSITE_CONNECTOR = 0x0401, - UVC_SVIDEO_CONNECTOR = 0x0402, - UVC_COMPONENT_CONNECTOR = 0x0403 -}; - -/** Status packet type (2.4.2.2) */ -enum uvc_status_type { - UVC_STATUS_TYPE_CONTROL = 1, - UVC_STATUS_TYPE_STREAMING = 2 -}; - -enum uvc_status_class { - UVC_STATUS_CLASS_CONTROL = 0x10, - UVC_STATUS_CLASS_CONTROL_CAMERA = 0x11, - UVC_STATUS_CLASS_CONTROL_PROCESSING = 0x12, -}; - -enum uvc_status_attribute { - UVC_STATUS_ATTRIBUTE_VALUE_CHANGE = 0x00, - UVC_STATUS_ATTRIBUTE_INFO_CHANGE = 0x01, - UVC_STATUS_ATTRIBUTE_FAILURE_CHANGE = 0x02, - UVC_STATUS_ATTRIBUTE_UNKNOWN = 0xff -}; - -enum uvc_frame_format { - UVC_FRAME_FORMAT_UNKNOWN = 0, - /** Any supported format */ - UVC_FRAME_FORMAT_ANY = 0, - UVC_FRAME_FORMAT_UNCOMPRESSED, - UVC_FRAME_FORMAT_COMPRESSED, - /** YUYV/YUV2/YUV422: YUV encoding with one luminance value per pixel and - * one UV (chrominance) pair for every two pixels. - */ - UVC_FRAME_FORMAT_YUYV, - UVC_FRAME_FORMAT_UYVY, - /** 24-bit RGB */ - UVC_FRAME_FORMAT_RGB, - UVC_FRAME_FORMAT_BGR, - /** Motion-JPEG (or JPEG) encoded images */ - UVC_FRAME_FORMAT_MJPEG, - UVC_FRAME_FORMAT_GRAY8, - UVC_FRAME_FORMAT_BY8, - /** Number of formats understood */ - UVC_FRAME_FORMAT_COUNT, -}; - -/** Payload header flags (2.4.3.3) */ -#define UVC_STREAM_EOH (1 << 7) -#define UVC_STREAM_ERR (1 << 6) -#define UVC_STREAM_STI (1 << 5) -#define UVC_STREAM_RES (1 << 4) -#define UVC_STREAM_SCR (1 << 3) -#define UVC_STREAM_PTS (1 << 2) -#define UVC_STREAM_EOF (1 << 1) -#define UVC_STREAM_FID (1 << 0) - -/** Control capabilities (4.1.2) */ -#define UVC_CONTROL_CAP_GET (1 << 0) -#define UVC_CONTROL_CAP_SET (1 << 1) -#define UVC_CONTROL_CAP_DISABLED (1 << 2) -#define UVC_CONTROL_CAP_AUTOUPDATE (1 << 3) -#define UVC_CONTROL_CAP_ASYNCHRONOUS (1 << 4) - -struct ucam_frame_desc { - /** Type of frame, such as JPEG frame or uncompressed frme */ - enum uvc_vs_desc_subtype bDescriptorSubtype; - /** Index of the frame within the list of specs available for this format */ - uint8_t bFrameIndex; - uint8_t bmCapabilities; - /** Image width */ - uint16_t wWidth; - /** Image height */ - uint16_t wHeight; - /** Bitrate of corresponding stream at minimal frame rate */ - uint32_t dwMinBitRate; - /** Bitrate of corresponding stream at maximal frame rate */ - uint32_t dwMaxBitRate; - /** Maximum number of bytes for a video frame */ - uint32_t dwMaxVideoFrameBufferSize; - /** Default frame interval (in 100ns units) */ - uint32_t dwDefaultFrameInterval; - /** Minimum frame interval for continuous mode (100ns units) */ - uint32_t dwMinFrameInterval; - /** Maximum frame interval for continuous mode (100ns units) */ - uint32_t dwMaxFrameInterval; - /** Granularity of frame interval range for continuous mode (100ns) */ - uint32_t dwFrameIntervalStep; - /** Frame intervals */ - uint8_t bFrameIntervalType; - /** number of bytes per line */ - uint32_t dwBytesPerLine; - /** Available frame rates, zero-terminated (in 100ns units) */ - uint32_t *intervals; -}; - -struct ucam_format_desc { - /** Type of image stream, such as JPEG or uncompressed. */ - enum uvc_vs_desc_subtype bDescriptorSubtype; - /** Identifier of this format within the VS interface's format list */ - uint8_t bFormatIndex; - uint8_t bNumFrameDescriptors; - /** Format specifier */ - union { - uint8_t guidFormat[16]; - uint8_t fourccFormat[4]; - }; - /** Format-specific data */ - union { - /** BPP for uncompressed stream */ - uint8_t bBitsPerPixel; - /** Flags for JPEG stream */ - uint8_t bmFlags; - }; - /** Default {uvc_frame_desc} to choose given this format */ - uint8_t bDefaultFrameIndex; - uint8_t bAspectRatioX; - uint8_t bAspectRatioY; - uint8_t bmInterlaceFlags; - uint8_t bCopyProtect; - uint8_t bVariableSize; - /** Available frame specifications for this format */ - struct ucam_frame_desc *frame_descs; -}; - -struct ucam_input_terminal { - /** Index of the terminal within the device */ - uint8_t bTerminalID; - /** Type of terminal (e.g., camera) */ - enum uvc_it_type wTerminalType; - uint16_t wObjectiveFocalLengthMin; - uint16_t wObjectiveFocalLengthMax; - uint16_t wOcularFocalLength; - /** Camera controls (meaning of bits given in {uvc_ct_ctrl_selector}) */ - uint64_t bmControls; -}; - -struct ucam_stream_ctrl { - uint16_t bmHint; - uint8_t bFormatIndex; - uint8_t bFrameIndex; - uint32_t dwFrameInterval; - uint16_t wKeyFrameRate; - uint16_t wPFrameRate; - uint16_t wCompQuality; - uint16_t wCompWindowSize; - uint16_t wDelay; - uint32_t dwMaxVideoFrameSize; - uint32_t dwMaxPayloadTransferSize; - uint32_t dwClockFrequency; - uint8_t bmFramingInfo; - uint8_t bPreferredVersion; - uint8_t bMinVersion; - uint8_t bMaxVersion; - uint8_t bInterfaceNumber; -}; - -struct ucam_frame { - /** Image data for this frame */ - void *data; - /** Size of image data buffer */ - size_t data_bytes; - /** Width of image in pixels */ - uint32_t width; - /** Height of image in pixels */ - uint32_t height; - /** Pixel data format */ - enum uvc_frame_format frame_format; - /** Number of bytes per horizontal line (undefined for compressed format) */ - size_t step; - /** Frame number (may skip, but is strictly monotonically increasing) */ - uint32_t sequence; - /** Estimate of system time when the device started capturing the image */ - struct timeval capture_time; - /** Handle on the device that produced the image. - * @warning You must not call any uvc_* functions during a callback. */ - //uvc_device_handle_t *source; - /** Is the data buffer owned by the library? - * If 1, the data buffer can be arbitrarily reallocated by frame conversion - * functions. - * If 0, the data buffer will not be reallocated or freed by the library. - * Set this field to zero if you are supplying the buffer. - */ - uint8_t library_owns_data; -} uvc_frame_t; - -struct ucam_ctrl { -#if 0 - struct uvc_device_info *parent; - struct uvc_input_terminal *input_term_descs; - // struct uvc_output_terminal *output_term_descs; - struct uvc_selector_unit *selector_unit_descs; - struct uvc_processing_unit *processing_unit_descs; - struct uvc_extension_unit *extension_unit_descs; -#endif - struct ucam_input_terminal term; - struct ucam_selector_unit { - /** Index of the selector unit within the device */ - uint8_t bUnitID; - } selector; - - struct ucam_processing_unit { - struct uvc_processing_unit *prev, *next; - /** Index of the processing unit within the device */ - uint8_t bUnitID; - /** Index of the terminal from which the device accepts images */ - uint8_t bSourceID; - /** Processing controls (meaning of bits given in {uvc_pu_ctrl_selector}) */ - uint64_t bmControls; - } processing; - - struct ucam_extension_unit { - /** Index of the extension unit within the device */ - uint8_t bUnitID; - /** GUID identifying the extension unit */ - uint8_t guidExtensionCode[16]; - /** Bitmap of available controls (manufacturer-dependent) */ - uint64_t bmControls; - } extension; - - uint16_t bcdUVC; - uint32_t dwClockFrequency; - uint8_t bEndpointAddress; - /** Interface number */ - uint8_t bInterfaceNumber; -}; - -struct ucam_stream { - /** Interface number */ - uint8_t bInterfaceNumber; - /** Video formats that this interface provides */ - struct uvc_format_desc *format_descs; - /** USB endpoint to use when communicating with this interface */ - uint8_t bEndpointAddress; - uint8_t bTerminalLink; -}; - -struct ucam_descriptor { - /** Vendor ID */ - uint16_t idVendor; - /** Product ID */ - uint16_t idProduct; - /** UVC compliance level, e.g. 0x0100 (1.0), 0x0110 */ - uint16_t bcdUVC; - /** Serial number (null if unavailable) */ - const char *serialNumber; - /** Device-reported manufacturer name (or null) */ - const char *manufacturer; - /** Device-reporter product name (or null) */ - const char *product; -}; - -struct ucam_dev_info { - struct libusb_config_descriptor *usb_conf; - struct ucam_ctrl control; - /** VideoStream interface */ - struct ucam_stream stream; - struct ucam_stream_ctrl stream_ctrl; - struct ucam_format_desc format; - struct ucam_frame_desc frame; - struct ucam_descriptor descriptor; -}; - -typedef void(ucam_frame_callback_t)(struct ucam_frame *frame, void *user_ptr); -typedef void(uvc_status_callback_t)(enum uvc_status_class status_class, - int event, - int selector, - enum uvc_status_attribute status_attribute, - void *data, size_t data_len, - void *user_ptr); - -typedef void(uvc_button_callback_t)(int button, - int state, - void *user_ptr); - - - -/* - set a high number of transfer buffers. This uses a lot of ram, but - avoids problems with scheduling delays on slow boards causing missed - transfers. A better approach may be to make the transfer thread FIFO - scheduled (if we have root). - We could/should change this to allow reduce it to, say, 5 by default - and then allow the user to change the number of buffers as required. - */ -#define LIBUVC_NUM_TRANSFER_BUFS 100 - -#define LIBUVC_XFER_BUF_SIZE ( 16 * 1024 * 1024 ) - -struct ucam_stream_handle { - struct uvc_device_handle *devh; - struct ucam_stream_handle *prev, *next; - struct uvc_streaming_interface *stream_if; - - /** if true, stream is running (streaming video to host) */ - uint8_t running; - /** Current control block */ - struct ucam_stream_ctrl cur_ctrl; - - /* listeners may only access hold*, and only when holding a - * lock on cb_mutex (probably signaled with cb_cond) */ - uint8_t fid; - uint32_t seq, hold_seq; - uint32_t pts, hold_pts; - uint32_t last_scr, hold_last_scr; - size_t got_bytes, hold_bytes; - uint8_t *outbuf, *holdbuf; - pthread_mutex_t cb_mutex; - pthread_cond_t cb_cond; - pthread_t cb_thread; - uint32_t last_polled_seq; - ucam_frame_callback_t *user_cb; - void *user_ptr; - struct libusb_transfer *transfers[LIBUVC_NUM_TRANSFER_BUFS]; - uint8_t *transfer_bufs[LIBUVC_NUM_TRANSFER_BUFS]; - struct ucam_frame frame; - enum uvc_frame_format frame_format; -}; - -#endif diff --git a/gear-lib/libuvc/v4l2.c b/gear-lib/libuvc/v4l2.c deleted file mode 100644 index f0c61eb..0000000 --- a/gear-lib/libuvc/v4l2.c +++ /dev/null @@ -1,1013 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2014-2020 Zhifeng Gong - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - ******************************************************************************/ -#include "libuvc.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * HAVE_LIBV4L2 will build with libv4l2 (v4l-utils) functions - */ -#if HAVE_LIBV4L2 -#include -#endif - -int (*open_f)(const char *file, int oflag, ...); -int (*close_f)(int fd); -int (*dup_f)(int fd); -int (*ioctl_f)(int fd, unsigned long int request, ...); -ssize_t (*read_f)(int fd, void *buffer, size_t n); -#if HAVE_LIBV4L2 -void *(*mmap_f)(void *start, size_t length, int prot, int flags, int fd, int64_t offset); -#else -void *(*mmap_f)(void *start, size_t length, int prot, int flags, int fd, off_t offset); -#endif -int (*munmap_f)(void *_start, size_t length); - -/* - * refer to /usr/include/linux/v4l2-controls.h - * supported v4l2 control cmds - */ -static const uint32_t v4l2_cid_supported[] = { - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_AUTO_WHITE_BALANCE, - V4L2_CID_GAMMA, - V4L2_CID_SHARPNESS, - V4L2_CID_LASTP1 -}; - -#define MAX_V4L2_CID (sizeof(v4l2_cid_supported)/sizeof(uint32_t)) -#define MAX_V4L_BUF (32) -#define MAX_V4L_REQBUF_CNT (4) -#define MAX_V4L2_DQBUF_RETYR_CNT (5) - -struct v4l2_ctx { - int fd; - int cancel_fd; - int channel; /*one video node may contain several input channel */ - int standard; - uint32_t pixfmt; - uint32_t linesize; - int dv_timing; - uint32_t width; - uint32_t height; - uint32_t fps_num; - uint32_t fps_den; - struct iovec buf[MAX_V4L_BUF]; - int buf_index; - int req_count; - bool qbuf_done; - uint64_t first_ts; - uint64_t frame_id; - struct v4l2_queryctrl controls[MAX_V4L2_CID]; - struct uvc_ctx *parent; - struct thread *thread; - bool is_streaming; - int epfd; - struct epoll_event events; -}; - -static int uvc_v4l2_init(struct v4l2_ctx *c); -static int uvc_v4l2_create_mmap(struct v4l2_ctx *c); -static int uvc_v4l2_set_format(int fd, uint32_t *w, uint32_t *h, uint32_t *pixelformat, uint32_t *bytesperline); -static int uvc_v4l2_set_framerate(int fd, uint32_t *fps_num, uint32_t *fps_den); -static int uvc_v4l2_start_stream(struct uvc_ctx *uvc); - - -#define V4L2_FOURCC_STR(code) \ - (char[5]) \ -{ \ - (code&0xFF), ((code>>8)&0xFF), ((code>>16)&0xFF), ((code>>24)&0xFF), 0 \ -} - -#define timeval2ns(tv) \ - (((uint64_t)tv.tv_sec * 1000000000) + ((uint64_t)tv.tv_usec * 1000)) - -static const struct v4l2_fourcc_pixel_format { - enum pixel_format pxl_fmt; - uint32_t v4l2_fmt; -} v4l2_fourcc_pixel_format_map [] = { - //pixel_format v4l2_format - {PIXEL_FORMAT_I420, V4L2_PIX_FMT_YVU420}, - {PIXEL_FORMAT_I420, V4L2_PIX_FMT_YUV420}, - {PIXEL_FORMAT_NV12, V4L2_PIX_FMT_NV12}, - {PIXEL_FORMAT_YVYU, V4L2_PIX_FMT_YVYU}, - {PIXEL_FORMAT_YUY2, V4L2_PIX_FMT_YUYV}, - {PIXEL_FORMAT_YUY2, V4L2_PIX_FMT_VYUY}, - {PIXEL_FORMAT_UYVY, V4L2_PIX_FMT_UYVY}, - {PIXEL_FORMAT_RGBA, 0}, - {PIXEL_FORMAT_BGRA, V4L2_PIX_FMT_ABGR32}, - {PIXEL_FORMAT_BGRX, V4L2_PIX_FMT_XBGR32}, - {PIXEL_FORMAT_Y800, 0}, - {PIXEL_FORMAT_I444, V4L2_PIX_FMT_YUV444}, - {PIXEL_FORMAT_BGR3, V4L2_PIX_FMT_BGR24}, - {PIXEL_FORMAT_I422, 0}, - {PIXEL_FORMAT_I40A, 0}, - {PIXEL_FORMAT_I42A, 0}, - {PIXEL_FORMAT_YUVA, 0}, - {PIXEL_FORMAT_AYUV, 0}, - {PIXEL_FORMAT_JPEG, V4L2_PIX_FMT_JPEG}, - {PIXEL_FORMAT_MJPG, V4L2_PIX_FMT_MJPEG}, - {PIXEL_FORMAT_MJPG, V4L2_PIX_FMT_SBGGR10P}, - {PIXEL_FORMAT_MAX, 0}, -}; - -static enum pixel_format v4l2fmt_to_pxlfmt(uint32_t v4l2_fmt) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(v4l2_fourcc_pixel_format_map); i++) { - if (v4l2_fourcc_pixel_format_map[i].v4l2_fmt == v4l2_fmt) - return v4l2_fourcc_pixel_format_map[i].pxl_fmt; - } - printf("v4l2fmt_to_pxlfmt %s failed!\n", V4L2_FOURCC_STR(v4l2_fmt)); - return PIXEL_FORMAT_NONE; -} - -static uint32_t pxlfmt_to_v4l2fmt(enum pixel_format pxl_fmt) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(v4l2_fourcc_pixel_format_map); i++) { - if (v4l2_fourcc_pixel_format_map[i].pxl_fmt == pxl_fmt) - return v4l2_fourcc_pixel_format_map[i].v4l2_fmt; - } - printf("pxlfmt_to_v4l2fmt %s failed!\n", pixel_format_to_string(pxl_fmt)); - return 0; -} - -static void *uvc_v4l2_open(struct uvc_ctx *uvc, const char *dev, struct uvc_config *conf) -{ - int fd = -1; - struct v4l2_ctx *c = calloc(1, sizeof(struct v4l2_ctx)); - if (!c) { - printf("malloc v4l2_ctx failed!\n"); - return NULL; - } - -#define SET_WRAPPERS(prefix) do { \ - open_f = prefix ## open; \ - close_f = prefix ## close; \ - dup_f = prefix ## dup; \ - ioctl_f = prefix ## ioctl; \ - read_f = prefix ## read; \ - mmap_f = prefix ## mmap; \ - munmap_f = prefix ## munmap; \ -} while (0) - - -#if HAVE_LIBV4L2 - SET_WRAPPERS(v4l2_); -#else - SET_WRAPPERS(); -#endif - -#define v4l2_open open_f -#define v4l2_close close_f -#define v4l2_dup dup_f -#define v4l2_ioctl ioctl_f -#define v4l2_read read_f -#define v4l2_mmap mmap_f -#define v4l2_munmap munmap_f - - fd = v4l2_open(dev, O_RDWR); - if (fd == -1) { - printf("open %s failed: %d\n", dev, errno); - goto failed; - } - c->fd = fd; - c->cancel_fd = eventfd(0, 0); - - c->channel = -1; - c->standard = -1; - c->dv_timing = -1; - c->width = conf->width; - c->height = conf->height; - c->pixfmt = pxlfmt_to_v4l2fmt(conf->format); - c->fps_num = conf->fps.num; - c->fps_den = conf->fps.den; - c->frame_id = 0; - - if (-1 == uvc_v4l2_init(c)) { - printf("uvc_v4l2_init failed\n"); - goto failed; - } - - if (uvc_v4l2_set_format(c->fd, &c->width, &c->height, &c->pixfmt, &c->linesize) < 0) { - printf("%s:%d uvc_v4l2_set_format failed %d\n", __func__, __LINE__, errno); - goto failed; - } - - if (uvc_v4l2_set_framerate(c->fd, &c->fps_num, &c->fps_den) < 0) { - printf("uvc_v4l2_set_framerate failed\n"); - //goto failed; - } - - if (uvc_v4l2_create_mmap(c) < 0) { - printf("uvc_v4l2_create_mmap failed\n"); - goto failed; - } - - uvc->conf.width = c->width; - uvc->conf.height = c->height; - uvc->conf.fps.num = c->fps_num; - uvc->conf.fps.den = c->fps_den; - uvc->conf.format = v4l2fmt_to_pxlfmt(c->pixfmt); - uvc->fd = fd; - c->parent = uvc; - return c; - -failed: - if (fd != -1) { - v4l2_close(fd); - } - if (c) { - free(c); - } - return NULL; -} - -static int uvc_v4l2_set_config(struct uvc_ctx *uvc, struct uvc_config *conf) -{ - struct v4l2_ctx *c = (struct v4l2_ctx *)uvc->opaque; - - c->width = conf->width; - c->height = conf->height; - c->fps_num = conf->fps.num; - c->fps_den = conf->fps.den; - c->pixfmt = pxlfmt_to_v4l2fmt(conf->format); - - if (uvc_v4l2_set_format(c->fd, &c->width, &c->height, &c->pixfmt, &c->linesize) < 0) { - printf("%s:%d uvc_v4l2_set_format failed %d\n", __func__, __LINE__, errno); - return -1; - } - - if (uvc_v4l2_set_framerate(c->fd, &c->fps_num, &c->fps_den) < 0) { - printf("uvc_v4l2_set_framerate failed\n"); - return -1; - } - - uvc->conf.width = c->width; - uvc->conf.height = c->height; - uvc->conf.fps.num = c->fps_num; - uvc->conf.fps.den = c->fps_den; - uvc->conf.format = v4l2fmt_to_pxlfmt(c->pixfmt); - return 0; -} - -static int v4l2_set_standard(int fd, int *standard) -{ - if (*standard == -1) { - if (v4l2_ioctl(fd, VIDIOC_G_STD, standard) < 0) { - printf("%s VIDIOC_G_STD failed: %d\n", __func__, errno); - return -1; - } - } else { - if (v4l2_ioctl(fd, VIDIOC_S_STD, standard) < 0) { - printf("%s VIDIOC_S_STD failed: %d\n", __func__, errno); - return -1; - } - } - - return 0; -} - -static int v4l2_enum_dv_timing(int dev, struct v4l2_dv_timings *dvt, - int index) -{ -#if !defined(VIDIOC_ENUM_DV_TIMINGS) || !defined(V4L2_IN_CAP_DV_TIMINGS) - UNUSED_PARAMETER(dev); - UNUSED_PARAMETER(dvt); - UNUSED_PARAMETER(index); - return -1; -#else - if (!dev || !dvt) - return -1; - - struct v4l2_enum_dv_timings iter; - memset(&iter, 0, sizeof(iter)); - iter.index = index; - - if (v4l2_ioctl(dev, VIDIOC_ENUM_DV_TIMINGS, &iter) < 0) { - printf("%s VIDIOC_ENUM_DV_TIMINGS failed: %d\n", __func__, errno); - return -1; - } - - memcpy(dvt, &iter.timings, sizeof(struct v4l2_dv_timings)); - - return 0; -#endif -} - -static int v4l2_set_dv_timing(int fd, int *timing) -{ - if (*timing == -1) - return 0; - - struct v4l2_dv_timings dvt; - - if (v4l2_enum_dv_timing(fd, &dvt, *timing) < 0) - return -1; - - if (v4l2_ioctl(fd, VIDIOC_S_DV_TIMINGS, &dvt) < 0) { - printf("%s VIDIOC_S_DV_TIMINGS failed: %d\n", __func__, errno); - return -1; - } - - return 0; -} - -static int v4l2_get_control(int fd, uint32_t id, int *val) -{ - struct v4l2_control vctrl; - - vctrl.id = id; - if (v4l2_ioctl(fd, VIDIOC_G_CTRL, &vctrl) < 0) { - printf("%s VIDIOC_G_CTRL failed: %d\n", __func__, errno); - return -1; - } - *val = vctrl.value; - return 0; -} - -static int v4l2_set_control(int fd, uint32_t id, int val) -{ - struct v4l2_control vctrl; - - vctrl.id = id; - vctrl.value = val; - if (v4l2_ioctl(fd, VIDIOC_S_CTRL, &vctrl) < 0) { - printf("%s VIDIOC_S_CTRL failed: %d\n", __func__, errno); - return -1; - } - return 0; -} - -static int uvc_v4l2_init(struct v4l2_ctx *c) -{ - struct v4l2_input in; - memset(&in, 0, sizeof(in)); - - if (v4l2_ioctl(c->fd, VIDIOC_G_INPUT, &in.index) < 0) { - printf("ioctl VIDIOC_G_INPUT failed:%d\n", errno); - return -1; - } - - if (v4l2_ioctl(c->fd, VIDIOC_ENUMINPUT, &in) < 0) { - printf("ioctl VIDIOC_ENUMINPUT failed\n"); - return -1; - } - - if (in.capabilities & V4L2_IN_CAP_STD) { - if (v4l2_set_standard(c->fd, &c->standard) < 0) { - printf("Unable to set video standard\n"); - return -1; - } - } - - if (in.capabilities & V4L2_IN_CAP_DV_TIMINGS) { - if (v4l2_set_dv_timing(c->fd, &c->dv_timing) < 0) { - printf("Unable to set dv timing\n"); - return -1; - } - } - return 0; -} - -static int uvc_v4l2_set_format(int fd, uint32_t *width, uint32_t *height, - uint32_t *pixelformat, uint32_t *bytesperline) -{ - bool update; - struct v4l2_format fmt; - - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (v4l2_ioctl(fd, VIDIOC_G_FMT, &fmt) < 0) { - printf("%s VIDIOC_G_FMT failed: %d\n", __func__, errno); - return -1; - } - - if (fmt.fmt.pix.width == *width && fmt.fmt.pix.height == *height && - fmt.fmt.pix.pixelformat == *pixelformat) { - update = false; - } else { - update = true; - fmt.fmt.pix.width = *width; - fmt.fmt.pix.height = *height; - fmt.fmt.pix.pixelformat = *pixelformat; - } - - if (update && v4l2_ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) { - printf("%s VIDIOC_S_FMT failed: %d\n", __func__, errno); - return -1; - } - - if (fmt.fmt.pix.width != *width || fmt.fmt.pix.height != *height) { - printf("v4l2 resolution force from %d*%d to %d*%d\n", - *width, *height, fmt.fmt.pix.width,fmt.fmt.pix.height); - } - - if (fmt.fmt.pix.pixelformat != *pixelformat) { - printf("v4l2 format force from %s to %s\n", - V4L2_FOURCC_STR(*pixelformat), - V4L2_FOURCC_STR(fmt.fmt.pix.pixelformat)); - } - - *width = fmt.fmt.pix.width; - *height = fmt.fmt.pix.height; - *pixelformat = fmt.fmt.pix.pixelformat; - *bytesperline = fmt.fmt.pix.bytesperline; - return 0; -} - -static int uvc_v4l2_set_framerate(int fd, uint32_t *fps_num, uint32_t *fps_den) -{ - bool update; - struct v4l2_streamparm par; - - par.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (v4l2_ioctl(fd, VIDIOC_G_PARM, &par) < 0) { - printf("%s VIDIOC_G_PARM failed:%d\n", __func__, errno); - return -1; - } - - if (par.parm.capture.timeperframe.numerator == *fps_den && - par.parm.capture.timeperframe.denominator == *fps_num) { - update = false; - } else { - update = true; - par.parm.capture.timeperframe.numerator = *fps_den; - par.parm.capture.timeperframe.denominator = *fps_num; - } - - if (update && v4l2_ioctl(fd, VIDIOC_S_PARM, &par) < 0) { - printf("%s VIDIOC_S_PARM failed:%d\n", __func__, errno); - return -1; - } - - if (par.parm.capture.timeperframe.numerator != *fps_den || - par.parm.capture.timeperframe.denominator != *fps_num) { - printf("v4l2 framerate force from %d/%d to %d/%d\n", - *fps_num, *fps_den, - par.parm.capture.timeperframe.denominator, - par.parm.capture.timeperframe.numerator); - } - *fps_den = par.parm.capture.timeperframe.numerator; - *fps_num = par.parm.capture.timeperframe.denominator; - return 0; -} - -static int uvc_v4l2_enqueue(struct uvc_ctx *uvc, void *buf, size_t len) -{ - struct v4l2_ctx *c = (struct v4l2_ctx *)uvc->opaque; - struct v4l2_buffer qbuf = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .memory = V4L2_MEMORY_MMAP, - .index = c->buf_index - }; - - if (c->qbuf_done) { - return 0; - } - if (v4l2_ioctl(c->fd, VIDIOC_QBUF, &qbuf) < 0) { - printf("%s ioctl(VIDIOC_QBUF) failed: %d\n", __func__, errno); - return -1; - } - c->qbuf_done = true; - return 0; -} - -static int uvc_v4l2_dequeue(struct uvc_ctx *uvc, struct video_frame *frame) -{ - int retry_cnt = 0; - uint8_t *start; - struct v4l2_buffer qbuf; - int i; - - struct v4l2_ctx *c = (struct v4l2_ctx *)uvc->opaque; - if (!c->qbuf_done) { - printf("v4l2 need VIDIOC_QBUF first!\n"); - return -1; - } - - memset(&qbuf, 0, sizeof(qbuf)); - qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - qbuf.memory = V4L2_MEMORY_MMAP; - -retry: - if (v4l2_ioctl(c->fd, VIDIOC_DQBUF, &qbuf) < 0) { - if (errno == EINTR || errno == EAGAIN) { - if (++retry_cnt > MAX_V4L2_DQBUF_RETYR_CNT) { - return -1; - } - goto retry; - } else { - printf("%s ioctl(VIDIOC_DQBUF) failed: %d\n", __func__, errno); - return -1; - } - } - - c->qbuf_done = false; - c->buf_index = qbuf.index; - - frame->timestamp = timeval2ns(qbuf.timestamp); - if (c->frame_id == 0) { - c->first_ts = frame->timestamp; - } - frame->timestamp -= c->first_ts; - frame->frame_id = c->frame_id; - c->frame_id++; - - start = (uint8_t *)c->buf[qbuf.index].iov_base; - - if (frame->mem_type == MEDIA_MEM_SHALLOW) {//frame data ptr - for (i = 0; i < frame->planes; ++i) { - frame->data[i] = start + frame->plane_offsets[i]; - } - } else if (frame->mem_type == MEDIA_MEM_DEEP) {//frame data copy - switch (frame->format) { - case PIXEL_FORMAT_YUY2: - memcpy(frame->data[0], start + frame->plane_offsets[0], frame->linesize[0]*frame->height); - break; - case PIXEL_FORMAT_I420: - memcpy(frame->data[0], start + frame->plane_offsets[0], frame->linesize[0]*frame->height); - memcpy(frame->data[1], start + frame->plane_offsets[1], frame->linesize[1]*frame->height / 2); - memcpy(frame->data[2], start + frame->plane_offsets[2], frame->linesize[2]*frame->height / 2); - break; - default: - break; - } - } - frame->total_size = qbuf.bytesused; - - return frame->total_size; -} - -static int uvc_v4l2_poll_init(struct v4l2_ctx *c) -{ - struct epoll_event epev; - memset(&epev, 0, sizeof(epev)); - c->epfd = epoll_create(1); - if (c->epfd == -1) { - printf("epoll_create failed %d!\n", errno); - return -1; - } - - epev.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET | EPOLLERR; - epev.data.ptr = (void *)c; - if (-1 == epoll_ctl(c->epfd, EPOLL_CTL_ADD, c->fd, &epev)) { - printf("epoll_ctl EPOLL_CTL_ADD failed %d!\n", errno); - return -1; - } - if (-1 == epoll_ctl(c->epfd, EPOLL_CTL_ADD, c->cancel_fd, &epev)) { - printf("epoll_ctl EPOLL_CTL_ADD failed %d!\n", errno); - return -1; - } - return 0; -} - -static int uvc_v4l2_poll(struct uvc_ctx *uvc, int timeout) -{ - struct v4l2_ctx *c = (struct v4l2_ctx *)uvc->opaque; - int ret = 0; - - int n = epoll_wait(c->epfd, &c->events, 1, timeout); - switch (n) { - case 0: - printf("poll timeout\n"); - ret = -1; - break; - case -1: - printf("poll error %d\n", errno); - ret = -1; - break; - default: - ret = 0; - break; - } - - return ret; -} - -static void uvc_v4l2_poll_deinit(struct v4l2_ctx *c) -{ - if (-1 == epoll_ctl(c->epfd, EPOLL_CTL_DEL, c->fd, NULL)) { - printf("epoll_ctl EPOLL_CTL_DEL failed %d!\n", errno); - } - close(c->epfd); -} - -static void *v4l2_thread(struct thread *t, void *arg) -{ - struct uvc_ctx *uvc = arg; - struct v4l2_ctx *c = (struct v4l2_ctx *)uvc->opaque; - struct video_frame frame; - - if (uvc_v4l2_poll_init(c) == -1) { - printf("uvc_v4l2_poll_init failed!\n"); - } - video_frame_init(&frame, uvc->conf.format, uvc->conf.width, uvc->conf.height, MEDIA_MEM_SHALLOW); - while (c->is_streaming) { - if (uvc_v4l2_enqueue(uvc, NULL, 0) != 0) { - printf("uvc_v4l2_enqueue failed\n"); - continue; - } - if (uvc_v4l2_poll(uvc, -1) != 0) { - printf("uvc_v4l2_poll failed\n"); - continue; - } - - if (uvc_v4l2_dequeue(uvc, &frame) == -1) { - printf("uvc_v4l2_dequeue failed\n"); - } - uvc->on_video_frame(uvc, &frame); - } - uvc_v4l2_poll_deinit(c); - return NULL; -} - -static int uvc_v4l2_start_stream(struct uvc_ctx *uvc) -{ - enum v4l2_buf_type type; - struct v4l2_buffer enq; - struct v4l2_ctx *c = (struct v4l2_ctx *)uvc->opaque; - - if (c->is_streaming) { - printf("v4l2 is streaming already!\n"); - return -1; - } - memset(&enq, 0, sizeof(enq)); - enq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - enq.memory = V4L2_MEMORY_MMAP; - - for (enq.index = 0; enq.index < c->req_count; ++enq.index) { - if (v4l2_ioctl(c->fd, VIDIOC_QBUF, &enq) < 0) { - printf("unable to queue buffer\n"); - return -1; - } - } - c->qbuf_done = true; - - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (v4l2_ioctl(c->fd, VIDIOC_STREAMON, &type) < 0) { - printf("unable to start stream\n"); - return -1; - } - - c->is_streaming = true; - if (uvc->on_video_frame) { - c->thread = thread_create(v4l2_thread, uvc); - if (!c->thread) { - printf("thread_create v4l2_thread failed!\n"); - return -1; - } - } - - return 0; -} - -static void uvc_v4l2_destroy_mmap(struct v4l2_ctx *c) -{ - for (int i = 0; i < c->req_count; ++i) { - if (c->buf[i].iov_base != MAP_FAILED && c->buf[i].iov_base != 0) - v4l2_munmap(c->buf[i].iov_base, c->buf[i].iov_len); - } - - if (c->req_count) { - c->req_count = 0; - } -} - -static int uvc_v4l2_stop_stream(struct uvc_ctx *uvc) -{ - uint64_t notify = '1'; - enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - struct v4l2_ctx *c = (struct v4l2_ctx *)uvc->opaque; - - if (!c->is_streaming) { - printf("v4l2 stream stopped already!\n"); - return -1; - } - - if (uvc->on_video_frame) { - c->is_streaming = false; - if (sizeof(uint64_t) != write(c->cancel_fd, ¬ify, sizeof(uint64_t))) { - perror("write error"); - } - thread_join(c->thread); - thread_destroy(c->thread); - } - - if (v4l2_ioctl(c->fd, VIDIOC_STREAMOFF, &type) < 0) { - printf("%s ioctl(VIDIOC_STREAMOFF) failed: %d\n", __func__, errno); - } - - return 0; -} - -static int uvc_v4l2_query_frame(struct uvc_ctx *uvc, struct video_frame *frame) -{ - if (uvc_v4l2_enqueue(uvc, NULL, 0) != 0) { - printf("uvc_v4l2_enqueue failed\n"); - return -1; - } - return uvc_v4l2_dequeue(uvc, frame); -} - -static int uvc_v4l2_create_mmap(struct v4l2_ctx *c) -{ - struct v4l2_buffer buf; - struct v4l2_requestbuffers req = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .count = MAX_V4L_REQBUF_CNT, - .memory = V4L2_MEMORY_MMAP - }; - //request buffer - if (v4l2_ioctl(c->fd, VIDIOC_REQBUFS, &req) < 0) { - printf("%s ioctl(VIDIOC_REQBUFS) failed: %d\n", __func__, errno); - return -1; - } - c->req_count = req.count; - if (req.count > MAX_V4L_REQBUF_CNT || req.count < 2) { - printf("Insufficient buffer memory\n"); - return -1; - } - - memset(&buf, 0, sizeof(buf)); - buf.type = req.type; - buf.memory = req.memory; - - for (buf.index = 0; buf.index < c->req_count; ++buf.index) { - //query buffer - if (v4l2_ioctl(c->fd, VIDIOC_QUERYBUF, &buf) < 0) { - printf("%s ioctl(VIDIOC_QUERYBUF) failed: %d\n", __func__, errno); - return -1; - } - //mmap buffer - c->buf[buf.index].iov_len = buf.length; - c->buf[buf.index].iov_base = - v4l2_mmap(NULL, buf.length, PROT_READ|PROT_WRITE, - MAP_SHARED, c->fd, buf.m.offset); - if (MAP_FAILED == c->buf[buf.index].iov_base) { - printf("mmap failed: %d\n", errno); - return -1; - } - } - return 0; -} - -static void uvc_v4l2_close(struct uvc_ctx *uvc) -{ - struct v4l2_ctx *c = (struct v4l2_ctx *)uvc->opaque; - //uvc_v4l2_stop_stream(uvc); - uvc_v4l2_destroy_mmap(c); - v4l2_close(c->fd); - close(c->epfd); - free(c); -} - -static int v4l2_get_input(struct v4l2_ctx *c) -{ - struct v4l2_input input; - struct v4l2_standard standard; - v4l2_std_id std_id; - - memset(&input, 0, sizeof(input)); - - if (v4l2_ioctl(c->fd, VIDIOC_G_INPUT, &input.index) < 0) { - printf("ioctl VIDIOC_G_INPUT failed\n"); - return -1; - } - if (v4l2_ioctl(c->fd, VIDIOC_ENUMINPUT, &input) < 0) { - printf("Unable to query input %d VIDIOC_ENUMINPUT," - "if you use a WEBCAM change input value in conf by -1", - input.index); - return -1; - } - c->channel = input.index; - - printf("[V4L2 Input information]:\n"); - printf("\tinput.name: \t\"%s\"\n", input.name); - if (0 == v4l2_ioctl(c->fd, VIDIOC_G_STD, &std_id)) { - memset(&standard, 0, sizeof(standard)); - standard.index = 0; - while (v4l2_ioctl(c->fd, VIDIOC_ENUMSTD, &standard) == 0) { - if (standard.id & std_id) - printf("\t\t- video standard %s\n", standard.name); - standard.index++; - } - printf("Set standard method %d\n", (int)std_id); - } - return 0; -} - -static int v4l2_get_cap(struct v4l2_ctx *c) -{ - struct v4l2_capability cap; - - if (v4l2_ioctl(c->fd, VIDIOC_QUERYCAP, &cap) < 0) { - printf("failed to VIDIOC_QUERYCAP\n"); - return -1; - } - - printf("[V4L2 Capability Information]:\n"); - printf("\tcap.driver: \t\"%s\"\n", cap.driver); - printf("\tcap.card: \t\"%s\"\n", cap.card); - printf("\tcap.bus_info: \t\"%s\"\n", cap.bus_info); - printf("\tcap.version: \t\"%d\"\n", cap.version); - printf("\tcap.capabilities: 0x%x\n", cap.capabilities); - if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) - printf("\t\t\t VIDEO_CAPTURE\n"); - if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) - printf("\t\t\t VIDEO_OUTPUT\n"); - if (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) - printf("\t\t\t VIDEO_OVERLAY\n"); - if (cap.capabilities & V4L2_CAP_VBI_CAPTURE) - printf("\t\t\t VBI_CAPTURE\n"); - if (cap.capabilities & V4L2_CAP_VBI_OUTPUT) - printf("\t\t\t VBI_OUTPUT\n"); - if (cap.capabilities & V4L2_CAP_RDS_CAPTURE) - printf("\t\t\t RDS_CAPTURE\n"); - if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_OVERLAY) - printf("\t\t\t VIDEO_OUTPUT_OVERLAY\n"); - if (cap.capabilities & V4L2_CAP_TUNER) - printf("\t\t\t TUNER\n"); - if (cap.capabilities & V4L2_CAP_AUDIO) - printf("\t\t\t AUDIO\n"); - if (cap.capabilities & V4L2_CAP_READWRITE) - printf("\t\t\t READWRITE\n"); - if (cap.capabilities & V4L2_CAP_ASYNCIO) - printf("\t\t\t ASYNCIO\n"); - if (cap.capabilities & V4L2_CAP_STREAMING) - printf("\t\t\t STREAMING\n"); - if (cap.capabilities & V4L2_CAP_TIMEPERFRAME) - printf("\t\t\t TIMEPERFRAME\n"); - if (cap.capabilities & V4L2_CAP_DEVICE_CAPS) - printf("\t\t\t DEVICE_CAPS\n"); - if (cap.capabilities & V4L2_CAP_EXT_PIX_FORMAT) - printf("\t\t\t EXT_PIX_FORMAT\n"); - - if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { - printf("Device does not support capturing.\n"); - return -1; - } - return 0; -} - -static void v4l2_get_fmt(struct v4l2_ctx *c) -{ - struct v4l2_fmtdesc fmtdesc; - fmtdesc.index = 0; - fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - printf("[V4L2 Support Format]:\n"); - while (0 == v4l2_ioctl(c->fd, VIDIOC_ENUM_FMT, &fmtdesc)) { - printf("\t%d. [%s] \"%s\"\n", fmtdesc.index, - V4L2_FOURCC_STR(fmtdesc.pixelformat), - fmtdesc.description); - ++fmtdesc.index; - } -} - -static void v4l2_get_cid(struct v4l2_ctx *c) -{ - int i; - struct v4l2_queryctrl *qctrl; - struct v4l2_control control; - printf("[V4L2 Supported Control]:\n"); - for (i = 0; i < MAX_V4L2_CID; i++) { - qctrl = &c->controls[i]; - qctrl->id = v4l2_cid_supported[i]; - if (v4l2_ioctl(c->fd, VIDIOC_QUERYCTRL, qctrl) < 0) { - continue; - } - memset(&control, 0, sizeof (control)); - control.id = v4l2_cid_supported[i]; - if (v4l2_ioctl(c->fd, VIDIOC_G_CTRL, &control) < 0) { - continue; - } - printf("\t%s, range: [%d, %d], default: %d, current: %d\n", - qctrl->name, - qctrl->minimum, qctrl->maximum, - qctrl->default_value, control.value); - } -} - -static int uvc_v4l2_print_info(struct v4l2_ctx *c) -{ - v4l2_get_input(c); - v4l2_get_cap(c); - v4l2_get_fmt(c); - v4l2_get_cid(c); - return 0; -} - -static int uvc_v4l2_ioctl(struct uvc_ctx *uvc, unsigned long int cmd, ...) -{ - void *arg; - va_list ap; - int ret = -1; - struct v4l2_ctx *c = (struct v4l2_ctx *)uvc->opaque; - - va_start(ap, cmd); - arg = va_arg(ap, void *); - va_end(ap); - - switch (cmd) { - case UVC_GET_CAP: - ret = uvc_v4l2_print_info(c); - break; - case UVC_SET_CONF: - ret = uvc_v4l2_set_config(uvc, (struct uvc_config *)arg); - break; - case UVC_SET_LUMA: - ret = v4l2_set_control(uvc->fd, V4L2_CID_BRIGHTNESS, *(int *)&arg); - break; - case UVC_GET_LUMA: - ret = v4l2_get_control(uvc->fd, V4L2_CID_BRIGHTNESS, (int *)arg); - break; - case UVC_SET_CTRST: - ret = v4l2_set_control(uvc->fd, V4L2_CID_CONTRAST, *(int *)&arg); - break; - case UVC_GET_CTRST: - ret = v4l2_get_control(uvc->fd, V4L2_CID_CONTRAST, (int *)arg); - break; - case UVC_SET_SAT: - ret = v4l2_set_control(uvc->fd, V4L2_CID_SATURATION, *(int *)&arg); - break; - case UVC_GET_SAT: - ret = v4l2_get_control(uvc->fd, V4L2_CID_SATURATION, (int *)arg); - break; - case UVC_SET_HUE: - ret = v4l2_set_control(uvc->fd, V4L2_CID_HUE, *(int *)&arg); - break; - case UVC_GET_HUE: - ret = v4l2_get_control(uvc->fd, V4L2_CID_HUE, (int *)arg); - break; - case UVC_SET_AWB: - ret = v4l2_set_control(uvc->fd, V4L2_CID_AUTO_WHITE_BALANCE, *(int *)&arg); - break; - case UVC_GET_AWB: - ret = v4l2_get_control(uvc->fd, V4L2_CID_AUTO_WHITE_BALANCE, (int *)arg); - break; - case UVC_SET_GAMMA: - ret = v4l2_set_control(uvc->fd, V4L2_CID_GAMMA, *(int *)&arg); - break; - case UVC_GET_GAMMA: - ret = v4l2_get_control(uvc->fd, V4L2_CID_GAMMA, (int *)arg); - break; - case UVC_SET_SHARP: - ret = v4l2_set_control(uvc->fd, V4L2_CID_SHARPNESS, *(int *)&arg); - break; - case UVC_GET_SHARP: - ret = v4l2_get_control(uvc->fd, V4L2_CID_SHARPNESS, (int *)arg); - break; - default: - printf("unsupport UVC cmd 0x%lx\n", cmd); - ret = -1; - break; - } - - return ret; -} - -struct uvc_ops v4l2_ops = { - ._open = uvc_v4l2_open, - ._close = uvc_v4l2_close, - .ioctl = uvc_v4l2_ioctl, - .start_stream = uvc_v4l2_start_stream, - .stop_stream = uvc_v4l2_stop_stream, - .query_frame = uvc_v4l2_query_frame, -};