因为工作需要使用libuvc调试一下摄像头,所以有了这次的实践机会,在这里分享一下如何在windows下通过msys2完成libuvc的使用。
一、安装MSYS2以及更新
首先找到msys2官网,下载msys2的安装程序,如下所示:
设置安装路径等步骤略。安装完成后可以搜索打开msys2 mingw64,如图所示:
打开之后输入以下命令,对msys2进行一个更新。
pacman -Syu
更新完成后需重启msys2,然后接着输入这一行命令,后续会弹出需要安装的包,可以直接按回车进行全量安装。
pacman -S base-devel mingw-w64-x86_64-toolchain mingw-w64-x86_64-libusb mingw-w64-x86_64-cmake
二、下载libuvc并完成安装
可以通过以下命令从github仓库克隆下libuvc,如果没有安装git可以直接搜索libuvc在github上直接下载安装包。
git clone https://github.com/libuvc/libuvc.git
克隆/下载项目之后,进入根目录找到CMakeLists.txt这个文件,对其间内容做一定的修改(否则会显示找不到libusb,实际上在前文中已经完成安装),修改后的CMakeLists.txt如下:
cmake_minimum_required(VERSION 3.1)
project(libuvc
VERSION 0.0.7
LANGUAGES C
)
# Additional search scripts path for libusb-1.0, libjpeg, OpenCV
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake)
# Xcode and Visual Studio do not using CMAKE_BUILD_TYPE cache variable
# so we use Release build type only with single configuration generators.
if (NOT CMAKE_CONFIGURATION_TYPES)
if(NOT CMAKE_BUILD_TYPE)
message(STATUS "No build type selected, default to Release")
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
endif()
endif()
if(NOT CMAKE_BUILD_TARGET)
message(STATUS "No target type selected, default to both shared and static library")
set(CMAKE_BUILD_TARGET "Both" CACHE STRING "" FORCE)
endif()
option(BUILD_EXAMPLE "Build example program" ON)
option(BUILD_TEST "Build test program" OFF)
option(ENABLE_UVC_DEBUGGING "Enable UVC debugging" OFF)
set(libuvc_DESCRIPTION "A cross-platform library for USB video devices")
set(libuvc_URL "https://github.com/libuvc/libuvc")
set(SOURCES
src/ctrl.c
src/ctrl-gen.c
src/device.c
src/diag.c
src/frame.c
src/init.c
src/stream.c
src/misc.c
)
# Locate the libusb-1.0 package manually if not found
find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h PATH_SUFFIXES libusb-1.0)
find_library(LIBUSB_LIBRARY NAMES usb-1.0 libusb-1.0)
if(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARY)
set(LIBUSB_FOUND TRUE)
set(LibUSB_INCLUDE_DIRS ${LIBUSB_INCLUDE_DIR})
set(LibUSB_LIBRARIES ${LIBUSB_LIBRARY})
else()
set(LIBUSB_FOUND FALSE)
message(WARNING "LibUSB not found. Please install it.")
endif()
# JpegPkg name to differ from shipped with CMake
find_package(JpegPkg QUIET)
if(JPEG_FOUND)
message(STATUS "Building libuvc with JPEG support.")
set(LIBUVC_HAS_JPEG TRUE)
list(APPEND SOURCES src/frame-mjpeg.c)
else()
message(WARNING "JPEG not found. libuvc will not support JPEG decoding.")
endif()
if(UNIX AND NOT APPLE)
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads REQUIRED)
set(threads Threads::Threads)
endif()
if(${CMAKE_BUILD_TARGET} MATCHES "Shared")
set(BUILD_UVC_SHARED TRUE)
elseif(${CMAKE_BUILD_TARGET} MATCHES "Static")
set(BUILD_UVC_STATIC TRUE)
elseif(${CMAKE_BUILD_TARGET} MATCHES "Both")
set(BUILD_UVC_SHARED TRUE)
set(BUILD_UVC_STATIC TRUE)
else()
message(FATAL_ERROR "Invalid build type ${CMAKE_BUILD_TARGET}" )
endif()
if(BUILD_UVC_SHARED)
add_library(uvc SHARED ${SOURCES})
set_target_properties(uvc PROPERTIES
VERSION ${libuvc_VERSION}
SOVERSION ${libuvc_VERSION_MAJOR}
# Exported name of target within namespace LibUVC
EXPORT_NAME UVCShared
)
list(APPEND UVC_TARGETS uvc)
if(NOT LibUVC_STATIC)
add_library(LibUVC::UVC ALIAS uvc)
endif()
# Aliases defined here available only if project included
# via addsubdirectory
add_library(LibUVC::UVCShared ALIAS uvc)
endif()
if(BUILD_UVC_STATIC)
add_library(uvc_static STATIC ${SOURCES})
set_target_properties(uvc_static PROPERTIES
OUTPUT_NAME uvc
# Exported name of target within namespace LibUVC
EXPORT_NAME UVCStatic
)
list(APPEND UVC_TARGETS uvc_static)
add_library(LibUVC::UVCStatic ALIAS uvc_static)
if(LibUVC_STATIC)
add_library(LibUVC::UVC ALIAS uvc_static)
endif()
endif()
configure_file(include/libuvc/libuvc_config.h.in
include/libuvc/libuvc_config.h
@ONLY
)
foreach(target_name IN LISTS UVC_TARGETS)
target_include_directories(${target_name}
PUBLIC
# Different paths for includes for build and install phase supported
# via INSTALL_INTERFACE and BUILD_INTERFACE generator expressions.
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
$<INSTALL_INTERFACE:include>
${LibUSB_INCLUDE_DIRS} # Add this line
)
target_link_libraries(${target_name}
# libusb-1.0 used internally so we link to it privately.
PRIVATE ${LibUSB_LIBRARIES} ${threads} # Modify this line
)
if(JPEG_FOUND)
target_link_libraries(${target_name}
PRIVATE ${JPEG_LIBRARIES}
)
endif()
set_target_properties(${target_name} PROPERTIES
PUBLIC_HEADER "include/libuvc/libuvc.h;${CMAKE_CURRENT_BINARY_DIR}/include/libuvc/libuvc_config.h"
)
if(ENABLE_UVC_DEBUGGING)
target_compile_definitions(${target_name}
PRIVATE
UVC_DEBUGGING
)
find_library(
log-lib
log
)
target_link_libraries(
${target_name}
PRIVATE
${log-lib}
)
endif()
endforeach()
if(BUILD_EXAMPLE)
add_executable(example src/example.c)
find_package(Threads)
target_link_libraries(example
PRIVATE
LibUVC::UVC
Threads::Threads
)
endif()
if(BUILD_TEST)
# OpenCV defines targets with transitive dependencies not with namespaces but using opencv_ prefix.
# This targets provide necessary include directories and linked flags.
find_package(OpenCVPkg REQUIRED
COMPONENTS
opencv_core
opencv_highgui
)
add_executable(uvc_test src/test.c)
target_link_libraries(uvc_test
PRIVATE
LibUVC::UVC
opencv_core
opencv_highgui
)
endif()
include(GNUInstallDirs)
set(CMAKE_INSTALL_CMAKEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/libuvc)
install(
TARGETS ${UVC_TARGETS}
EXPORT libuvcTargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libuvc
)
install(EXPORT libuvcTargets
FILE libuvcTargets.cmake
NAMESPACE LibUVC::
DESTINATION ${CMAKE_INSTALL_CMAKEDIR}
)
install(FILES
cmake/FindLibUSB.cmake
cmake/FindJpegPkg.cmake
DESTINATION ${CMAKE_INSTALL_CMAKEDIR}
)
include(CMakePackageConfigHelpers)
write_basic_package_version_file(libuvcConfigVersion.cmake
COMPATIBILITY AnyNewerVersion
)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/libuvcConfigVersion.cmake
DESTINATION ${CMAKE_INSTALL_CMAKEDIR}
)
if(JPEG_FOUND)
# If we have used JPEG library we need to
# add linker flag for it in config file for pkgconfig
set(PKGCONFIG_JPEG_LDFLAG "-ljpeg")
endif()
configure_file(libuvc.pc.in
${PROJECT_BINARY_DIR}/libuvc.pc
@ONLY
)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/libuvc.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
)
install(FILES libuvcConfig.cmake
DESTINATION ${CMAKE_INSTALL_CMAKEDIR}
)
然后在msys2控制台对libuvc的根目录执行下列命令:
mkdir build
cd build
cmake -G "MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=$HOME/libuvc -DBUILD_SHARED_LIBS=ON ..
make
make install
-DCMAKE_INSTALL_PREFIX=$HOME/libuvc ..是指定安装路径
例如我的msys2安装在E盘的msys2文件夹下,该参数会使后续make install将.a文件安装在这个目录下:
E:/msys2/home/*****/libuvc/lib/********
三、编写测试程序
这是我编写的调用libuvc的测试程序camera.c
#include <stdio.h>
#include <libuvc/libuvc.h>
#include <unistd.h> // 引入unistd.h以使用usleep函数
// 回调函数,用于处理捕获到的每一帧
void cb(uvc_frame_t *frame, void *ptr) {
uvc_frame_t *bgr;
uvc_error_t ret;
// 分配一个新的帧用于BGR格式
bgr = uvc_allocate_frame(frame->width * frame->height * 3);
if (!bgr) {
printf("Unable to allocate BGR frame!\n");
return;
}
// 将帧转换为BGR格式
ret = uvc_any2bgr(frame, bgr);
if (ret) {
uvc_perror(ret, "uvc_any2bgr");
uvc_free_frame(bgr);
return;
}
printf("Frame received! Width: %u, Height: %u\n", frame->width, frame->height);
// 在这里处理BGR格式的帧
// ...
uvc_free_frame(bgr);
}
int main() {
uvc_context_t *ctx;
uvc_device_t *dev;
uvc_device_handle_t *devh;
uvc_stream_ctrl_t ctrl;
uvc_error_t res;
// 初始化libuvc库
res = uvc_init(&ctx, NULL);
if (res < 0) {
uvc_perror(res, "uvc_init");
return res;
}
// 查找连接到计算机的第一个UVC设备
res = uvc_find_device(ctx, &dev, 0, 0, NULL);
if (res < 0) {
uvc_perror(res, "uvc_find_device");
uvc_exit(ctx);
return res;
}
printf("Device found\n");
// 打开UVC设备
res = uvc_open(dev, &devh);
if (res < 0) {
uvc_perror(res, "uvc_open");
uvc_unref_device(dev);
uvc_exit(ctx);
return res;
}
printf("Device opened\n");
// 获取流控制器,用于设置帧格式和帧率
res = uvc_get_stream_ctrl_format_size(
devh, &ctrl, UVC_FRAME_FORMAT_YUYV, 640, 480, 30
);
if (res < 0) {
uvc_perror(res, "uvc_get_stream_ctrl_format_size");
uvc_close(devh);
uvc_unref_device(dev);
uvc_exit(ctx);
return res;
}
printf("Stream control format set\n");
// 开始视频流
res = uvc_start_streaming(devh, &ctrl, cb, (void *)ctx, 0);
if (res < 0) {
uvc_perror(res, "uvc_start_streaming");
uvc_close(devh);
uvc_unref_device(dev);
uvc_exit(ctx);
return res;
}
printf("Streaming...\n");
// 等待10秒钟以捕获一些帧
usleep(10 * 1000000); // usleep函数以微秒为单位
// 停止视频流
uvc_stop_streaming(devh);
// 关闭设备,释放资源
uvc_close(devh);
uvc_unref_device(dev);
uvc_exit(ctx);
printf("Done\n");
return 0;
}
链接、编译成.exe
gcc -o camera camera.c -I$HOME/libuvc/include -L$HOME/libuvc/lib -luvc -lusb-1.0
复制libuvc.dll文件到当前文件夹/设置环境变量(二选一)后,运行.exe文件
# 复制dll文件
cp $HOME/libuvc/bin/libuvc.dll /e/WorkSpace/video/test/ #目标目录
# 添加到环境变量
export PATH=$HOME/libuvc/lib:$PATH
./camera
这样就大功告成了