| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729 |
- #include "capture_video_capturer.h"
- #include "../base/logger.h"
- #include "../base/media_common.h"
- #include <algorithm>
- #include <sstream>
- #ifdef _WIN32
- #include <windows.h>
- #include <dshow.h>
- #pragma comment(lib, "strmiids.lib")
- #endif
- extern "C" {
- #include <libavformat/avformat.h>
- #include <libavdevice/avdevice.h>
- #include <libswscale/swscale.h>
- #include <libavutil/imgutils.h>
- #include <libavutil/opt.h>
- }
- namespace av {
- namespace capture {
- VideoCapturer::VideoCapturer() : videoParams_(CapturerType::VIDEO_CAMERA) {
- AV_LOGGER_DEBUG("创建视频采集器");
-
- // 注册设备
- avdevice_register_all();
- }
- VideoCapturer::~VideoCapturer() {
- close();
- AV_LOGGER_DEBUG("视频采集器已销毁");
- }
- ErrorCode VideoCapturer::initialize(const CapturerParams& params) {
- if (params.mediaType != MediaType::VIDEO) {
- AV_LOGGER_ERROR("参数媒体类型不是视频");
- return ErrorCode::INVALID_ARGUMENT;
- }
-
- videoParams_ = static_cast<const VideoCaptureParams&>(params);
-
- if (!validateParams(videoParams_)) {
- return ErrorCode::INVALID_PARAMS;
- }
-
- ErrorCode result = ErrorCode::OK;
-
- if (videoParams_.type == CapturerType::VIDEO_CAMERA) {
- result = initializeCamera();
- } else if (videoParams_.type == CapturerType::VIDEO_SCREEN) {
- result = initializeScreen();
- } else {
- AV_LOGGER_ERROR("不支持的视频采集器类型");
- return ErrorCode::NOT_SUPPORTED;
- }
-
- if (result == ErrorCode::OK) {
- setState(CapturerState::INITIALIZED);
- AV_LOGGER_INFOF("视频采集器初始化成功: {}x{}@{}fps",
- videoParams_.width, videoParams_.height, videoParams_.fps);
- }
-
- return result;
- }
- ErrorCode VideoCapturer::start() {
- std::lock_guard<std::mutex> lock(captureMutex_);
-
- if (getState() != CapturerState::INITIALIZED) {
- AV_LOGGER_ERROR("采集器状态无效,无法启动");
- return ErrorCode::INVALID_STATE;
- }
-
- shouldStop_ = false;
-
- // 启动采集线程
- try {
- captureThread_ = std::thread(&VideoCapturer::captureThreadFunc, this);
- setState(CapturerState::STARTED);
-
- AV_LOGGER_INFO("视频采集已启动");
- return ErrorCode::OK;
- } catch (const std::exception& e) {
- AV_LOGGER_ERRORF("启动采集线程失败: {}", e.what());
- return ErrorCode::THREAD_ERROR;
- }
- }
- ErrorCode VideoCapturer::stop() {
- std::lock_guard<std::mutex> lock(captureMutex_);
-
- if (getState() != CapturerState::STARTED) {
- return ErrorCode::OK;
- }
-
- shouldStop_ = true;
-
- // 唤醒暂停的线程
- {
- std::lock_guard<std::mutex> pauseLock(pauseMutex_);
- paused_ = false;
- pauseCondition_.notify_all();
- }
-
- // 等待线程结束
- if (captureThread_.joinable()) {
- captureThread_.join();
- }
-
- setState(CapturerState::STOPPED);
- AV_LOGGER_INFO("视频采集已停止");
-
- return ErrorCode::OK;
- }
- ErrorCode VideoCapturer::pause() {
- if (getState() != CapturerState::STARTED) {
- return ErrorCode::INVALID_STATE;
- }
-
- paused_ = true;
- AV_LOGGER_INFO("视频采集已暂停");
-
- return ErrorCode::OK;
- }
- ErrorCode VideoCapturer::resume() {
- if (getState() != CapturerState::STARTED) {
- return ErrorCode::INVALID_STATE;
- }
-
- {
- std::lock_guard<std::mutex> lock(pauseMutex_);
- paused_ = false;
- pauseCondition_.notify_all();
- }
-
- AV_LOGGER_INFO("视频采集已恢复");
-
- return ErrorCode::OK;
- }
- ErrorCode VideoCapturer::reset() {
- ErrorCode result = stop();
- if (result != ErrorCode::OK) {
- return result;
- }
-
- // 清空帧队列
- {
- std::lock_guard<std::mutex> lock(queueMutex_);
- while (!frameQueue_.empty()) {
- frameQueue_.pop();
- }
- }
-
- resetStats();
- setState(CapturerState::INITIALIZED);
-
- AV_LOGGER_INFO("视频采集器已重置");
-
- return ErrorCode::OK;
- }
- ErrorCode VideoCapturer::close() {
- stop();
-
- // 清理资源
- cleanupConverter();
-
- if (codecCtx_) {
- avcodec_free_context(&codecCtx_);
- codecCtx_ = nullptr;
- }
-
- if (formatCtx_) {
- avformat_close_input(&formatCtx_);
- formatCtx_ = nullptr;
- }
-
- codec_ = nullptr;
- videoStreamIndex_ = -1;
-
- setState(CapturerState::IDLE);
- AV_LOGGER_INFO("视频采集器已关闭");
-
- return ErrorCode::OK;
- }
- std::vector<std::string> VideoCapturer::getAvailableDevices() const {
- std::vector<std::string> devices;
- auto deviceInfos = getDetailedDeviceInfo();
-
- for (const auto& info : deviceInfos) {
- devices.push_back(info.name);
- }
-
- return devices;
- }
- std::string VideoCapturer::getCurrentDevice() const {
- return videoParams_.deviceName;
- }
- std::vector<VideoDeviceInfo> VideoCapturer::getDetailedDeviceInfo() const {
- std::lock_guard<std::mutex> lock(deviceCacheMutex_);
-
- if (!devicesCached_) {
- if (videoParams_.type == CapturerType::VIDEO_CAMERA) {
- cachedDevices_ = enumerateCameras();
- } else if (videoParams_.type == CapturerType::VIDEO_SCREEN) {
- cachedDevices_ = enumerateScreens();
- }
- devicesCached_ = true;
- }
-
- return cachedDevices_;
- }
- ErrorCode VideoCapturer::setVideoParams(int width, int height, int fps) {
- if (getState() == CapturerState::STARTED) {
- AV_LOGGER_ERROR("无法在采集过程中修改参数");
- return ErrorCode::INVALID_STATE;
- }
-
- videoParams_.width = width;
- videoParams_.height = height;
- videoParams_.fps = fps;
-
- AV_LOGGER_INFOF("视频参数已更新: {}x{}@{}fps", width, height, fps);
-
- return ErrorCode::OK;
- }
- ErrorCode VideoCapturer::setPixelFormat(AVPixelFormat format) {
- if (getState() == CapturerState::STARTED) {
- AV_LOGGER_ERROR("无法在采集过程中修改像素格式");
- return ErrorCode::INVALID_STATE;
- }
-
- videoParams_.pixelFormat = format;
-
- AV_LOGGER_INFOF("像素格式已更新: {}", av_get_pix_fmt_name(format));
-
- return ErrorCode::OK;
- }
- VideoCaptureParams VideoCapturer::getCurrentParams() const {
- return videoParams_;
- }
- bool VideoCapturer::validateParams(const CapturerParams& params) {
- const auto& videoParams = static_cast<const VideoCaptureParams&>(params);
-
- if (videoParams.width <= 0 || videoParams.height <= 0) {
- AV_LOGGER_ERROR("视频分辨率无效");
- return false;
- }
-
- if (videoParams.fps <= 0 || videoParams.fps > 120) {
- AV_LOGGER_ERROR("帧率无效");
- return false;
- }
-
- if (videoParams.type == CapturerType::VIDEO_CAMERA) {
- if (videoParams.cameraIndex < 0) {
- AV_LOGGER_ERROR("摄像头索引无效");
- return false;
- }
- } else if (videoParams.type == CapturerType::VIDEO_SCREEN) {
- if (videoParams.screenIndex < 0) {
- AV_LOGGER_ERROR("屏幕索引无效");
- return false;
- }
- }
-
- return true;
- }
- ErrorCode VideoCapturer::initializeCamera() {
- AV_LOGGER_INFOF("初始化摄像头采集器: 索引={}", videoParams_.cameraIndex);
-
- #ifdef _WIN32
- return setupDirectShowCamera();
- #elif defined(__linux__)
- return setupV4L2Camera();
- #elif defined(__APPLE__)
- return setupAVFoundationCamera();
- #else
- AV_LOGGER_ERROR("当前平台不支持摄像头采集");
- return ErrorCode::NOT_SUPPORTED;
- #endif
- }
- ErrorCode VideoCapturer::initializeScreen() {
- AV_LOGGER_INFOF("初始化屏幕录制: 索引={}", videoParams_.screenIndex);
-
- #ifdef _WIN32
- return setupGDIScreenCapture();
- #elif defined(__linux__)
- return setupX11ScreenCapture();
- #elif defined(__APPLE__)
- return setupCoreGraphicsScreenCapture();
- #else
- AV_LOGGER_ERROR("当前平台不支持屏幕录制");
- return ErrorCode::NOT_SUPPORTED;
- #endif
- }
- ErrorCode VideoCapturer::openInputDevice() {
- const AVInputFormat* inputFormat = getPlatformInputFormat();
- if (!inputFormat) {
- AV_LOGGER_ERROR("获取输入格式失败");
- return ErrorCode::NOT_SUPPORTED;
- }
-
- std::string deviceName = getPlatformDeviceName();
- if (deviceName.empty()) {
- AV_LOGGER_ERROR("获取设备名称失败");
- return ErrorCode::DEVICE_NOT_FOUND;
- }
-
- AV_LOGGER_INFOF("打开输入设备: {} (格式: {})", deviceName, inputFormat->name);
-
- // 设置输入选项
- AVDictionary* options = nullptr;
-
- // 设置视频参数
- av_dict_set(&options, "video_size",
- (std::to_string(videoParams_.width) + "x" + std::to_string(videoParams_.height)).c_str(), 0);
- av_dict_set(&options, "framerate", std::to_string(videoParams_.fps).c_str(), 0);
-
- if (videoParams_.type == CapturerType::VIDEO_SCREEN) {
- // 屏幕录制特定选项
- if (videoParams_.captureCursor) {
- av_dict_set(&options, "draw_mouse", "1", 0);
- }
-
- if (videoParams_.offsetX != 0 || videoParams_.offsetY != 0) {
- av_dict_set(&options, "offset_x", std::to_string(videoParams_.offsetX).c_str(), 0);
- av_dict_set(&options, "offset_y", std::to_string(videoParams_.offsetY).c_str(), 0);
- }
- }
-
- // 打开输入
- int ret = avformat_open_input(&formatCtx_, deviceName.c_str(), inputFormat, &options);
- av_dict_free(&options);
-
- if (ret < 0) {
- AV_LOGGER_ERRORF("打开输入设备失败: {} (设备: {})",
- ffmpeg_utils::errorToString(ret), deviceName);
- return static_cast<ErrorCode>(ret);
- }
-
- // 查找流信息
- ret = avformat_find_stream_info(formatCtx_, nullptr);
- if (ret < 0) {
- AV_LOGGER_ERRORF("查找流信息失败: {}", ffmpeg_utils::errorToString(ret));
- return static_cast<ErrorCode>(ret);
- }
-
- // 查找视频流
- videoStreamIndex_ = av_find_best_stream(formatCtx_, AVMEDIA_TYPE_VIDEO, -1, -1, &codec_, 0);
- if (videoStreamIndex_ < 0) {
- AV_LOGGER_ERROR("未找到视频流");
- return ErrorCode::STREAM_NOT_FOUND;
- }
-
- // 创建解码上下文
- codecCtx_ = avcodec_alloc_context3(codec_);
- if (!codecCtx_) {
- AV_LOGGER_ERROR("分配解码上下文失败");
- return ErrorCode::OUT_OF_MEMORY;
- }
-
- // 复制流参数到解码上下文
- ret = avcodec_parameters_to_context(codecCtx_, formatCtx_->streams[videoStreamIndex_]->codecpar);
- if (ret < 0) {
- AV_LOGGER_ERRORF("复制流参数失败: {}", ffmpeg_utils::errorToString(ret));
- return static_cast<ErrorCode>(ret);
- }
-
- // 打开解码器
- ret = avcodec_open2(codecCtx_, codec_, nullptr);
- if (ret < 0) {
- AV_LOGGER_ERRORF("打开解码器失败: {}", ffmpeg_utils::errorToString(ret));
- return static_cast<ErrorCode>(ret);
- }
-
- // 设置像素格式转换
- return setupPixelFormatConversion();
- }
- ErrorCode VideoCapturer::setupPixelFormatConversion() {
- AVPixelFormat srcFormat = codecCtx_->pix_fmt;
- AVPixelFormat dstFormat = videoParams_.pixelFormat;
-
- needConversion_ = (srcFormat != dstFormat);
-
- if (needConversion_) {
- AV_LOGGER_INFOF("需要像素格式转换: {} -> {}",
- av_get_pix_fmt_name(srcFormat),
- av_get_pix_fmt_name(dstFormat));
-
- swsCtx_ = sws_getContext(
- codecCtx_->width, codecCtx_->height, srcFormat,
- videoParams_.width, videoParams_.height, dstFormat,
- SWS_BILINEAR, nullptr, nullptr, nullptr
- );
-
- if (!swsCtx_) {
- AV_LOGGER_ERROR("创建像素格式转换上下文失败");
- return ErrorCode::CONVERSION_ERROR;
- }
-
- // 创建转换后的帧
- convertedFrame_ = makeAVFrame();
- if (!convertedFrame_) {
- return ErrorCode::OUT_OF_MEMORY;
- }
-
- convertedFrame_->format = dstFormat;
- convertedFrame_->width = videoParams_.width;
- convertedFrame_->height = videoParams_.height;
-
- int ret = av_frame_get_buffer(convertedFrame_.get(), 32);
- if (ret < 0) {
- AV_LOGGER_ERRORF("分配转换帧缓冲区失败: {}", ffmpeg_utils::errorToString(ret));
- return static_cast<ErrorCode>(ret);
- }
- }
-
- return ErrorCode::OK;
- }
- void VideoCapturer::captureThreadFunc() {
- AV_LOGGER_INFO("视频采集线程已启动");
-
- while (!shouldStop_) {
- // 检查暂停状态
- {
- std::unique_lock<std::mutex> lock(pauseMutex_);
- pauseCondition_.wait(lock, [this] { return !paused_ || shouldStop_; });
- }
-
- if (shouldStop_) {
- break;
- }
-
- ErrorCode result = captureFrame();
- if (result != ErrorCode::OK) {
- onError(result, "采集帧失败");
-
- // 短暂休眠后重试
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- }
- }
-
- AV_LOGGER_INFO("视频采集线程已退出");
- }
- ErrorCode VideoCapturer::captureFrame() {
- AVPacket packet;
- av_init_packet(&packet);
-
- // 读取包
- int ret = av_read_frame(formatCtx_, &packet);
- if (ret < 0) {
- if (ret == AVERROR_EOF) {
- AV_LOGGER_WARNING("到达文件末尾");
- return ErrorCode::END_OF_STREAM;
- } else {
- AV_LOGGER_ERRORF("读取帧失败: {}", ffmpeg_utils::errorToString(ret));
- return static_cast<ErrorCode>(ret);
- }
- }
-
- // 检查是否是视频包
- if (packet.stream_index != videoStreamIndex_) {
- av_packet_unref(&packet);
- return ErrorCode::OK;
- }
-
- // 发送包到解码器
- ret = avcodec_send_packet(codecCtx_, &packet);
- av_packet_unref(&packet);
-
- if (ret < 0) {
- AV_LOGGER_ERRORF("发送包到解码器失败: {}", ffmpeg_utils::errorToString(ret));
- return static_cast<ErrorCode>(ret);
- }
-
- // 接收解码后的帧
- AVFramePtr frame = makeAVFrame();
- if (!frame) {
- return ErrorCode::OUT_OF_MEMORY;
- }
-
- ret = avcodec_receive_frame(codecCtx_, frame.get());
- if (ret == AVERROR(EAGAIN)) {
- return ErrorCode::OK; // 需要更多输入
- } else if (ret < 0) {
- AV_LOGGER_ERRORF("接收解码帧失败: {}", ffmpeg_utils::errorToString(ret));
- return static_cast<ErrorCode>(ret);
- }
-
- // 像素格式转换
- AVFramePtr outputFrame;
- if (needConversion_) {
- outputFrame = convertPixelFormat(frame);
- if (!outputFrame) {
- return ErrorCode::CONVERSION_ERROR;
- }
- } else {
- outputFrame = frame;
- }
-
- // 添加到队列或直接回调
- onFrameCaptured(outputFrame);
-
- return ErrorCode::OK;
- }
- AVFramePtr VideoCapturer::convertPixelFormat(const AVFramePtr& srcFrame) {
- if (!srcFrame || !swsCtx_ || !convertedFrame_) {
- return nullptr;
- }
-
- // 执行像素格式转换
- int ret = sws_scale(swsCtx_,
- srcFrame->data, srcFrame->linesize, 0, srcFrame->height,
- convertedFrame_->data, convertedFrame_->linesize);
-
- if (ret < 0) {
- AV_LOGGER_ERRORF("像素格式转换失败: {}", ffmpeg_utils::errorToString(ret));
- return nullptr;
- }
-
- // 复制时间戳等信息
- av_frame_copy_props(convertedFrame_.get(), srcFrame.get());
-
- return convertedFrame_;
- }
- void VideoCapturer::cleanupConverter() {
- if (swsCtx_) {
- sws_freeContext(swsCtx_);
- swsCtx_ = nullptr;
- }
-
- convertedFrame_.reset();
- needConversion_ = false;
- }
- std::vector<VideoDeviceInfo> VideoCapturer::enumerateCameras() const {
- #ifdef _WIN32
- return enumerateDirectShowDevices();
- #elif defined(__linux__)
- return enumerateV4L2Devices();
- #elif defined(__APPLE__)
- return enumerateAVFoundationDevices();
- #else
- return {};
- #endif
- }
- std::vector<VideoDeviceInfo> VideoCapturer::enumerateScreens() const {
- std::vector<VideoDeviceInfo> screens;
-
- // 简单的屏幕枚举实现
- VideoDeviceInfo screen;
- screen.id = "desktop";
- screen.name = "桌面";
- screen.description = "主显示器";
-
- // 添加常见分辨率
- screen.supportedResolutions = {
- {1920, 1080}, {1680, 1050}, {1600, 900}, {1440, 900},
- {1366, 768}, {1280, 1024}, {1280, 800}, {1024, 768}
- };
-
- // 添加常见帧率
- screen.supportedFps = {15, 24, 30, 60};
-
- // 添加支持的像素格式
- screen.supportedFormats = {
- AV_PIX_FMT_BGR24, AV_PIX_FMT_BGRA, AV_PIX_FMT_YUV420P
- };
-
- screens.push_back(screen);
-
- return screens;
- }
- const AVInputFormat* VideoCapturer::getPlatformInputFormat() const {
- #ifdef _WIN32
- if (videoParams_.type == CapturerType::VIDEO_CAMERA) {
- return av_find_input_format("dshow");
- } else if (videoParams_.type == CapturerType::VIDEO_SCREEN) {
- return av_find_input_format("gdigrab");
- }
- #elif defined(__linux__)
- if (videoParams_.type == CapturerType::VIDEO_CAMERA) {
- return av_find_input_format("v4l2");
- } else if (videoParams_.type == CapturerType::VIDEO_SCREEN) {
- return av_find_input_format("x11grab");
- }
- #elif defined(__APPLE__)
- if (videoParams_.type == CapturerType::VIDEO_CAMERA) {
- return av_find_input_format("avfoundation");
- } else if (videoParams_.type == CapturerType::VIDEO_SCREEN) {
- return av_find_input_format("avfoundation");
- }
- #endif
-
- return nullptr;
- }
- std::string VideoCapturer::getPlatformDeviceName() const {
- #ifdef _WIN32
- if (videoParams_.type == CapturerType::VIDEO_CAMERA) {
- if (!videoParams_.deviceName.empty()) {
- return "video=" + videoParams_.deviceName;
- } else {
- return "video=" + std::to_string(videoParams_.cameraIndex);
- }
- } else if (videoParams_.type == CapturerType::VIDEO_SCREEN) {
- return "desktop";
- }
- #elif defined(__linux__)
- if (videoParams_.type == CapturerType::VIDEO_CAMERA) {
- if (!videoParams_.deviceName.empty()) {
- return videoParams_.deviceName;
- } else {
- return "/dev/video" + std::to_string(videoParams_.cameraIndex);
- }
- } else if (videoParams_.type == CapturerType::VIDEO_SCREEN) {
- return ":0.0";
- }
- #elif defined(__APPLE__)
- if (videoParams_.type == CapturerType::VIDEO_CAMERA) {
- return std::to_string(videoParams_.cameraIndex);
- } else if (videoParams_.type == CapturerType::VIDEO_SCREEN) {
- return "Capture screen 0";
- }
- #endif
-
- return "";
- }
- #ifdef _WIN32
- std::vector<VideoDeviceInfo> VideoCapturer::enumerateDirectShowDevices() const {
- std::vector<VideoDeviceInfo> devices;
-
- // 简化的DirectShow设备枚举
- // 实际实现需要使用COM接口
- VideoDeviceInfo device;
- device.id = "0";
- device.name = "默认摄像头";
- device.description = "DirectShow摄像头设备";
-
- // 添加常见分辨率
- device.supportedResolutions = {
- {1920, 1080}, {1280, 720}, {960, 540}, {640, 480}, {320, 240}
- };
-
- // 添加常见帧率
- device.supportedFps = {15, 24, 30, 60};
-
- // 添加支持的像素格式
- device.supportedFormats = {
- AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUYV422, AV_PIX_FMT_BGR24
- };
-
- devices.push_back(device);
-
- return devices;
- }
- ErrorCode VideoCapturer::setupDirectShowCamera() {
- AV_LOGGER_INFO("设置DirectShow摄像头");
- return openInputDevice();
- }
- ErrorCode VideoCapturer::setupGDIScreenCapture() {
- AV_LOGGER_INFO("设置GDI屏幕录制");
- return openInputDevice();
- }
- #endif
- // VideoCaptureFactory 实现
- std::unique_ptr<VideoCapturer> VideoCapturer::VideoCaptureFactory::createCamera(int cameraIndex) {
- auto capturer = std::make_unique<VideoCapturer>();
-
- VideoCaptureParams params(CapturerType::VIDEO_CAMERA);
- params.cameraIndex = cameraIndex;
-
- ErrorCode result = capturer->initialize(params);
- if (result != ErrorCode::OK) {
- AV_LOGGER_ERRORF("创建摄像头采集器失败: {}", static_cast<int>(result));
- return nullptr;
- }
-
- return capturer;
- }
- std::unique_ptr<VideoCapturer> VideoCapturer::VideoCaptureFactory::createScreen(int screenIndex) {
- auto capturer = std::make_unique<VideoCapturer>();
-
- VideoCaptureParams params(CapturerType::VIDEO_SCREEN);
- params.screenIndex = screenIndex;
-
- ErrorCode result = capturer->initialize(params);
- if (result != ErrorCode::OK) {
- AV_LOGGER_ERRORF("创建屏幕录制采集器失败: {}", static_cast<int>(result));
- return nullptr;
- }
-
- return capturer;
- }
- std::unique_ptr<VideoCapturer> VideoCapturer::VideoCaptureFactory::createBestCamera() {
- return createCamera(0); // 默认使用第一个摄像头
- }
- } // namespace capture
- } // namespace av
|