SDL3_API分类参考_摄像头(CategoryCamera)

2026-3-6 / 0 评论 / 5 阅读

摄像头子系统(CategoryCamera)

SDL 库提供的视频采集功能,专门用于读取摄像头(如网络摄像头)等视频源的输入数据。

通过这组 API,应用可实现以下功能:

  • 枚举、查询系统中的摄像头设备;
  • 打开摄像头并获取逐帧视频数据(以 SDL_Surface 形式返回);
  • 将视频帧上传至 SDL_Texture 渲染,或直接处理内存中的像素数据。

权限说明

多数平台会对摄像头访问做权限管控:

  • 应用首次访问摄像头时,系统会弹出 UI 向用户请求授权;
  • 授权结果可通过两种方式获取:
    1. 主动查询:调用 SDL_GetCameraPermissionState()
    2. 事件监听:等待 SDL_EVENT_CAMERA_DEVICE_APPROVED(授权通过)或 SDL_EVENT_CAMERA_DEVICE_DENIED(授权拒绝)事件;
  • 无权限管控的平台会立即返回「授权通过」状态,摄像头打开后即可获取帧数据。

功能限制

  1. SDL 摄像头仅提供原始视频帧,不输出编码后的视频文件(应用可自行将帧编码为任意格式);
  2. 该 API 不提供摄像头硬件的音频数据:
    • 多数摄像头无麦克风;
    • 即使有,直播/视频通话等场景通常也需独立麦克风;
    • 音频采集需通过 SDL 音频 API 实现,与摄像头硬件无关。

摄像头使用注意事项

消费级摄像头设备打开后需要「预热时间」:

  • 刚打开的摄像头可能先输出几帧全黑画面,或曝光不足的图像;
  • 若需自动抓拍单帧、或无预览直接录制视频,建议丢弃前几帧(甚至前几秒)的数据,再使用有效帧。

函数

  • SDL_AcquireCameraFrame:获取摄像头的最新视频帧(返回 SDL_Surface 指针,用完需调用 Release 释放)
  • SDL_CloseCamera:关闭已打开的摄像头设备(释放摄像头资源)
  • SDL_GetCameraDriver:获取指定索引的摄像头驱动名称(如 "uvc" 表示 USB 视频类驱动)
  • SDL_GetCameraFormat:获取摄像头当前使用的视频格式(分辨率、像素格式、帧率等)
  • SDL_GetCameraID:获取摄像头设备的唯一标识 ID(SDL_CameraID 类型)
  • SDL_GetCameraName:获取摄像头设备的友好名称(如 "USB Camera (046d:0825)")
  • SDL_GetCameraPermissionState:查询摄像头的权限状态(授权中/已授权/已拒绝,参考 SDL_CameraPermissionState)
  • SDL_GetCameraPosition:获取摄像头的物理位置(前置/后置/未指定,参考 SDL_CameraPosition)
  • SDL_GetCameraProperties:获取摄像头的详细属性(如支持的最大分辨率、是否自动对焦等)
  • SDL_GetCameras:枚举系统中的所有摄像头设备(返回设备列表及数量)
  • SDL_GetCameraSupportedFormats:获取摄像头支持的所有视频格式(分辨率、帧率、像素格式组合)
  • SDL_GetCurrentCameraDriver:获取当前正在使用的摄像头驱动名称
  • SDL_GetNumCameraDrivers:获取系统中可用的摄像头驱动数量
  • SDL_OpenCamera:打开指定的摄像头设备(传入设备 ID 和期望的视频格式,返回 SDL_Camera 句柄)
  • SDL_ReleaseCameraFrame:释放已获取的摄像头视频帧(与 Acquire 成对使用,避免内存泄漏)

数据类型

  • SDL_Camera:摄像头设备句柄类型(标识已打开的摄像头)
  • SDL_CameraID:摄像头设备唯一标识类型(用于区分不同摄像头)

结构体

  • SDL_CameraSpec:摄像头规格结构体(指定期望的分辨率、帧率、像素格式等参数)

枚举

  • SDL_CameraPermissionState:摄像头权限状态枚举(SDL_CAMERA_PERMISSION_UNKNOWN/GRANTED/DENIED/PENDING)
  • SDL_CameraPosition:摄像头物理位置枚举(SDL_CAMERA_POSITION_UNKNOWN/FRONT/BACK)

  • (无)

FreeBASIC 示例代码

' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL3 库)
#Include "SDL.bi"

' 错误处理辅助函数
Sub CheckError(ByVal msg As String)
    Dim As ZString Ptr err = SDL_GetError()
    If (*err <> 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "%s:%s", msg, err)
        SDL_ClearError()
        End 1
    End If
End Sub

' 主程序
Dim As SDL_CameraID Ptr cameraIDs = NULL
Dim As Integer cameraCount = 0
Dim As SDL_Camera Ptr camera = NULL
Dim As SDL_CameraSpec cameraSpec
Dim As SDL_Surface Ptr frame = NULL
Dim As SDL_Window Ptr window = NULL
Dim As SDL_Renderer Ptr renderer = NULL
Dim As SDL_Texture Ptr texture = NULL
Dim As SDL_Rect dstRect
Dim As SDL_CameraPermissionState permState
Dim As Integer quit = 0, frameCount = 0
Dim As SDL_Event evt

' 1. 初始化 SDL(需启用视频子系统)
If (SDL_Init(SDL_INIT_VIDEO) < 0) Then
    SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "SDL 初始化失败:%s", SDL_GetError())
    End 1
End If

' 2. 枚举系统中的摄像头设备
cameraCount = SDL_GetCameras(0, NULL)
If (cameraCount <= 0) Then
    SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "未检测到摄像头设备")
    SDL_Quit()
    End 1
End If
SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "检测到 %d 个摄像头设备", cameraCount)

' 分配内存并获取摄像头 ID 列表
cameraIDs = Callocate(cameraCount * SizeOf(SDL_CameraID))
cameraCount = SDL_GetCameras(cameraCount, cameraIDs)
For i As Integer = 0 To cameraCount - 1
    Dim As ZString Ptr camName = SDL_GetCameraName(cameraIDs[i])
    SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "摄像头 %d:%s", i, camName)
    SDL_free(camName)  ' 释放名称字符串
Next

' 3. 配置摄像头规格(期望 640x480,30fps,RGBA8888 格式)
cameraSpec.w = 640
cameraSpec.h = 480
cameraSpec.fps = 30
cameraSpec.format = SDL_PIXELFORMAT_RGBA8888

' 4. 打开第一个摄像头
camera = SDL_OpenCamera(cameraIDs[0], @cameraSpec)
If (camera = NULL) Then
    CheckError("打开摄像头失败")
    GoTo cleanup
End If
SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "摄像头已打开,等待权限授权...")

' 5. 等待摄像头权限授权(循环查询直到授权完成)
Do
    permState = SDL_GetCameraPermissionState(camera)
    Select Case permState
        Case SDL_CAMERA_PERMISSION_GRANTED
            SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "摄像头权限已授权")
            Exit Do
        Case SDL_CAMERA_PERMISSION_DENIED
            SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "摄像头权限被拒绝")
            GoTo cleanup
        Case SDL_CAMERA_PERMISSION_PENDING
            SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "权限请求中...")
            SDL_Delay(500)
        Case Else
            SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "权限状态未知,默认授权")
            Exit Do
    End Select
Loop

' 6. 创建窗口和渲染器(用于显示摄像头画面)
window = SDL_CreateWindow("SDL 摄像头示例", _
    SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _
    640, 480, SDL_WINDOW_SHOWN)
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED)
If (window = NULL Or renderer = NULL) Then
    CheckError("创建窗口/渲染器失败")
    GoTo cleanup
End If
dstRect = Type<SDL_Rect>(0, 0, 640, 480)

SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "=== 摄像头预览开始 ===")
SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "按 ESC 退出 | 摄像头预热中,前几帧可能黑屏")

' 7. 主循环:获取并渲染摄像头帧
While (quit = 0)
    ' 处理事件
    While (SDL_PollEvent(@evt))
        Select Case evt.type
            Case SDL_QUITEVENT
                quit = 1
            Case SDL_KEYDOWN
                If (evt.key.keysym.sym = SDLK_ESCAPE) Then
                    quit = 1
                End If
            ' 监听摄像头权限事件(可选)
            Case SDL_EVENT_CAMERA_DEVICE_APPROVED
                SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "收到摄像头授权通过事件")
            Case SDL_EVENT_CAMERA_DEVICE_DENIED
                SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "收到摄像头授权拒绝事件")
                quit = 1
        End Select
    Wend

    ' 获取摄像头帧(非阻塞)
    frame = SDL_AcquireCameraFrame(camera)
    If (frame <> NULL) Then
        frameCount += 1

        ' 跳过前 10 帧预热数据
        If (frameCount > 10) Then
            ' 创建/更新纹理
            If (texture = NULL) Then
                texture = SDL_CreateTextureFromSurface(renderer, frame)
            Else
                SDL_UpdateTexture(texture, NULL, frame->pixels, frame->pitch)
            End If

            ' 渲染纹理
            SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255)
            SDL_RenderClear(renderer)
            SDL_RenderTexture(renderer, texture, NULL, @dstRect)
            SDL_RenderPresent(renderer)
        End If

        ' 释放帧(必须调用,否则摄像头会阻塞)
        SDL_ReleaseCameraFrame(camera, frame)
    End If

    SDL_Delay(10)  ' 控制循环频率
Wend

' 8. 清理资源
cleanup:
' 释放纹理/渲染器/窗口
If (texture <> NULL) Then SDL_DestroyTexture(texture)
If (renderer <> NULL) Then SDL_DestroyRenderer(renderer)
If (window <> NULL) Then SDL_DestroyWindow(window)

' 关闭摄像头
If (camera <> NULL) Then
    SDL_CloseCamera(camera)
    SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "摄像头已关闭")
End If

' 释放摄像头 ID 列表
If (cameraIDs <> NULL) Then
    Deallocate(cameraIDs)
End If

' 退出 SDL
SDL_Quit()
SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "程序正常退出,共渲染 %d 帧", frameCount - 10)
End 0

总结

  1. SDL 摄像头子系统核心流程:SDL_GetCameras 枚举设备 → SDL_OpenCamera 打开设备 → SDL_AcquireCameraFrame 获取帧 → SDL_ReleaseCameraFrame 释放帧;
  2. FreeBASIC 中使用时需注意:
    • 必须处理权限状态(SDL_GetCameraPermissionState 或监听授权事件);
    • 摄像头帧需「获取-释放」成对使用,且建议跳过前几帧预热数据;
    • 帧数据(SDL_Surface)可转换为 SDL_Texture 渲染,或直接处理像素;
  3. 关键限制:仅输出原始视频帧,无音频/编码功能,音频需通过 SDL 音频 API 单独采集。

评论一下?

OωO
取消