1.remove libuvc and libuac, replace with libavcap

2.update libbitmap from kernel
3.update libstrex
This commit is contained in:
gozfree
2022-05-16 00:26:05 +08:00
parent 3cdb944f80
commit c9deef0f62
38 changed files with 1907 additions and 6429 deletions

View File

@@ -44,7 +44,7 @@
## 多媒体
| | |
|--|--|
| libuvc: USB摄像头库 | libmp4: MP4录制解析库 |
| libavcap: 音频视频捕获库 | libmp4: MP4录制解析库 |
| libjpeg-ex: | libmedia-io: 音频视频格式定义 |
## 系统抽象层

View File

@@ -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

View File

@@ -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"

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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
```

View File

@@ -0,0 +1,171 @@
#include "libavcap.h"
#include <libthread.h>
#include <liblog.h>
#include <esp_camera.h>
#include <esp_log.h>
#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,
};

View File

@@ -5,6 +5,23 @@
#include <asm/types.h>
#include "kernel.h"
//#include <linux/compiler.h>
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)

View File

@@ -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 <stdarg.h>
#include <stddef.h>
@@ -9,9 +10,24 @@
#include <endian.h>
#include <byteswap.h>
#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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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})

View File

@@ -19,7 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
******************************************************************************/
#include <libuvc.h>
#include <libavcap.h>
#include <liblog.h>
#include <libdarray.h>
#include <libtime.h>
@@ -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();

View File

@@ -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',

View File

@@ -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);

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)*

View File

@@ -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

View File

@@ -1,102 +0,0 @@
/******************************************************************************
* Copyright (C) 2014-2020 Zhifeng Gong <gozfree@163.com>
*
* 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 <stdio.h>
#include <stdlib.h>
#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);
}

View File

@@ -1,85 +0,0 @@
/******************************************************************************
* Copyright (C) 2014-2020 Zhifeng Gong <gozfree@163.com>
*
* 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 <libposix.h>
#include <libmedia-io.h>
#include <stdio.h>
#include <stdint.h>
#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

File diff suppressed because it is too large Load Diff

View File

@@ -1,73 +0,0 @@
/******************************************************************************
* Copyright (C) 2014-2020 Zhifeng Gong <gozfree@163.com>
*
* 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 <libfile.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#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;
}

View File

@@ -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)

View File

@@ -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})

View File

@@ -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)

View File

@@ -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)*

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -1,245 +0,0 @@
#ifndef DSHOW_H
#define DSHOW_H
#define COBJMACROS
#define CINTERFACE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <dshow.h>
#include <strmif.h>
#include <dvdmedia.h>
#include <uuids.h>
#include <control.h>
#include <objidl.h>
#include <shlwapi.h>
#include <vfwmsgs.h>
#include <stdint.h>
#include <wchar.h>
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

View File

@@ -1,339 +0,0 @@
/******************************************************************************
* Copyright (C) 2014-2020 Zhifeng Gong <gozfree@163.com>
*
* 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 <libthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/stat.h>
#include <sys/eventfd.h>
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, &notify, 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, &notify, 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, &notify, 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, &notify, 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,
};

View File

@@ -1,165 +0,0 @@
/******************************************************************************
* Copyright (C) 2014-2020 Zhifeng Gong <gozfree@163.com>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <stdarg.h>
#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);
}

View File

@@ -1,127 +0,0 @@
/******************************************************************************
* Copyright (C) 2014-2020 Zhifeng Gong <gozfree@163.com>
*
* 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 <libposix.h>
#include <libmedia-io.h>
#include <stdio.h>
#include <stdint.h>
#if defined (OS_LINUX)
#define __USE_LINUX_IOCTL_DEFS
#include <sys/ioctl.h>
#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

View File

@@ -1,134 +0,0 @@
/******************************************************************************
* Copyright (C) 2014-2020 Zhifeng Gong <gozfree@163.com>
*
* 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 <libfile.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,458 +0,0 @@
/******************************************************************************
* Copyright (C) 2014-2020 Zhifeng Gong <gozfree@163.com>
*
* 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

File diff suppressed because it is too large Load Diff