#include "codec_video_encoder.h" #include "../base/logger.h" #include #include extern "C" { #include #include #include } namespace av { namespace codec { // 静态成员初始化 std::vector VideoEncoder::supportedEncoders_; std::once_flag VideoEncoder::encodersInitFlag_; // PixelFormatConverter 实现 PixelFormatConverter::PixelFormatConverter(AVPixelFormat srcFormat, AVPixelFormat dstFormat) : swsCtx_(nullptr) , srcFormat_(srcFormat) , dstFormat_(dstFormat) , width_(0) , height_(0) { } PixelFormatConverter::~PixelFormatConverter() { if (swsCtx_) { sws_freeContext(swsCtx_); } } bool PixelFormatConverter::setSize(int width, int height) { if (width_ == width && height_ == height && swsCtx_) { return true; } width_ = width; height_ = height; if (swsCtx_) { sws_freeContext(swsCtx_); } swsCtx_ = sws_getContext( width, height, srcFormat_, width, height, dstFormat_, SWS_BILINEAR, nullptr, nullptr, nullptr ); if (!swsCtx_) { AV_LOGGER_ERRORF("创建像素格式转换器失败: {}x{} format:{} -> {}", width, height, static_cast(srcFormat_), static_cast(dstFormat_)); return false; } // 创建目标帧 dstFrame_ = makeAVFrame(); if (!dstFrame_) { AV_LOGGER_ERROR("分配目标帧失败"); return false; } dstFrame_->format = dstFormat_; dstFrame_->width = width; dstFrame_->height = height; if (av_frame_get_buffer(dstFrame_.get(), 32) < 0) { AV_LOGGER_ERROR("分配帧缓冲区失败"); return false; } return true; } AVFramePtr PixelFormatConverter::convert(const AVFramePtr& srcFrame) { if (!srcFrame || !swsCtx_) { return nullptr; } if (!setSize(srcFrame->width, srcFrame->height)) { return nullptr; } // 复制时间戳等信息 av_frame_copy_props(dstFrame_.get(), srcFrame.get()); // 执行格式转换 int ret = sws_scale( swsCtx_, srcFrame->data, srcFrame->linesize, 0, srcFrame->height, dstFrame_->data, dstFrame_->linesize ); if (ret < 0) { AV_LOGGER_ERRORF("像素格式转换失败: {}", ffmpeg_utils::errorToString(ret)); return nullptr; } // 创建一个新的帧来返回,避免拷贝构造 AVFramePtr resultFrame = makeAVFrame(); if (!resultFrame) { return nullptr; } // 复制帧数据 if (av_frame_ref(resultFrame.get(), dstFrame_.get()) < 0) { return nullptr; } return resultFrame; } // VideoEncoder 实现 VideoEncoder::VideoEncoder() : AbstractEncoder(MediaType::VIDEO) , isHardwareEncoder_(false) , hwDeviceCtx_(nullptr) { AV_LOGGER_DEBUG("创建视频编码器"); } VideoEncoder::~VideoEncoder() { close(); AV_LOGGER_DEBUG("视频编码器已销毁"); } ErrorCode VideoEncoder::open(const CodecParams& params) { std::lock_guard lock(encodeMutex_); if (state_ != CodecState::IDLE && state_ != CodecState::CLOSED) { AV_LOGGER_WARNING("编码器已打开,先关闭再重新打开"); close(); } if (!validateParams(params)) { return ErrorCode::INVALID_PARAMS; } videoParams_ = static_cast(params); params_ = params; ErrorCode result = initEncoder(); if (result != ErrorCode::SUCCESS) { close(); return result; } setState(CodecState::OPENED); AV_LOGGER_INFOF("视频编码器已打开: {} ({}x{} @ {}fps)", videoParams_.codecName, videoParams_.width, videoParams_.height, videoParams_.fps); return ErrorCode::SUCCESS; } void VideoEncoder::close() { std::lock_guard lock(encodeMutex_); if (state_ == CodecState::CLOSED || state_ == CodecState::IDLE) { return; } // 清理硬件资源 if (hwDeviceCtx_) { av_buffer_unref(&hwDeviceCtx_); hwDeviceCtx_ = nullptr; } hwFrame_.reset(); convertedFrame_.reset(); converter_.reset(); // 清理编解码上下文 codecCtx_.reset(); codec_ = nullptr; setState(CodecState::CLOSED); AV_LOGGER_DEBUG("视频编码器已关闭"); } ErrorCode VideoEncoder::flush() { std::lock_guard lock(encodeMutex_); if (state_ != CodecState::OPENED && state_ != CodecState::RUNNING) { return ErrorCode::INVALID_STATE; } setState(CodecState::FLUSHING); // 发送空帧来刷新编码器 int ret = avcodec_send_frame(codecCtx_.get(), nullptr); if (ret < 0 && ret != AVERROR_EOF) { AV_LOGGER_ERRORF("刷新编码器失败: {}", ffmpeg_utils::errorToString(ret)); reportError(static_cast(ret)); return static_cast(ret); } setState(CodecState::OPENED); return ErrorCode::SUCCESS; } ErrorCode VideoEncoder::encode(const AVFramePtr& frame, std::vector& packets) { std::lock_guard lock(encodeMutex_); if (state_ != CodecState::OPENED && state_ != CodecState::RUNNING) { return ErrorCode::INVALID_STATE; } setState(CodecState::RUNNING); auto startTime = std::chrono::high_resolution_clock::now(); ErrorCode result = encodeFrame(frame, packets); auto endTime = std::chrono::high_resolution_clock::now(); double processTime = std::chrono::duration(endTime - startTime).count(); updateStats(result == ErrorCode::SUCCESS, processTime, frame ? frame->width * frame->height * 3 / 2 : 0); if (frameCallback_ && frame) { frameCallback_(frame); } for (const auto& packet : packets) { if (packetCallback_) { packetCallback_(packet); } } return result; } ErrorCode VideoEncoder::finishEncode(std::vector& packets) { return flush(); } bool VideoEncoder::validateParams(const CodecParams& params) { if (params.type != MediaType::VIDEO) { AV_LOGGER_ERROR("参数媒体类型不是视频"); return false; } const auto& videoParams = static_cast(params); if (videoParams.width <= 0 || videoParams.height <= 0) { AV_LOGGER_ERROR("视频尺寸无效"); return false; } if (videoParams.fps <= 0) { AV_LOGGER_ERROR("帧率无效"); return false; } if (videoParams.bitRate <= 0) { AV_LOGGER_ERROR("比特率无效"); return false; } if (videoParams.codecName.empty()) { AV_LOGGER_ERROR("编码器名称为空"); return false; } return true; } ErrorCode VideoEncoder::initEncoder() { // 查找编码器 codec_ = avcodec_find_encoder_by_name(videoParams_.codecName.c_str()); if (!codec_) { AV_LOGGER_ERRORF("未找到编码器: {}", videoParams_.codecName); return ErrorCode::CODEC_NOT_FOUND; } if (codec_->type != AVMEDIA_TYPE_VIDEO) { AV_LOGGER_ERROR("编码器类型不是视频"); return ErrorCode::INVALID_PARAMS; } // 创建编码上下文 codecCtx_ = makeAVCodecContext(codec_); if (!codecCtx_) { AV_LOGGER_ERROR("分配编码上下文失败"); return ErrorCode::MEMORY_ALLOC_FAILED; } // 设置硬件加速 if (videoParams_.hardwareAccel && isHardwareEncoder(videoParams_.codecName)) { ErrorCode result = setupHardwareAcceleration(); if (result != ErrorCode::SUCCESS) { AV_LOGGER_WARNING("硬件加速设置失败,回退到软件编码"); isHardwareEncoder_ = false; // 清理硬件资源 if (hwDeviceCtx_) { av_buffer_unref(&hwDeviceCtx_); hwDeviceCtx_ = nullptr; } } } // 设置编码器参数(在硬件加速设置之后) ErrorCode result = setupEncoderParams(); if (result != ErrorCode::SUCCESS) { return result; } // 打开编码器前的详细日志 AV_LOGGER_INFOF("准备打开编码器: {}", videoParams_.codecName); AV_LOGGER_INFOF("编码器参数: {}x{}, 比特率: {}, 帧率: {}, 像素格式: {}", codecCtx_->width, codecCtx_->height, codecCtx_->bit_rate, codecCtx_->framerate.num, static_cast(codecCtx_->pix_fmt)); if (isHardwareEncoder_) { AV_LOGGER_INFOF("硬件编码器状态: 设备上下文={}, 帧上下文={}", hwDeviceCtx_ ? "已创建" : "未创建", codecCtx_->hw_frames_ctx ? "已设置" : "未设置"); } // 验证编码器参数 if (codecCtx_->width <= 0 || codecCtx_->height <= 0) { AV_LOGGER_ERROR("无效的视频尺寸参数"); return ErrorCode::INVALID_PARAMS; } if (codecCtx_->bit_rate <= 0) { AV_LOGGER_ERROR("无效的比特率参数"); return ErrorCode::INVALID_PARAMS; } // 打开编码器 int ret = avcodec_open2(codecCtx_.get(), codec_, nullptr); if (ret < 0) { AV_LOGGER_ERRORF("打开编码器失败: {} (错误码: {})", ffmpeg_utils::errorToString(ret), ret); // 详细错误分析 if (ret == AVERROR(EINVAL)) { AV_LOGGER_ERROR("编码器参数无效 - 可能的原因:"); AV_LOGGER_ERROR(" 1. 不支持的像素格式或分辨率组合"); AV_LOGGER_ERROR(" 2. 硬件编码器参数配置错误"); AV_LOGGER_ERROR(" 3. 硬件设备上下文与编码器不匹配"); } else if (ret == AVERROR(EBUSY)) { AV_LOGGER_ERROR("硬件设备忙碌 - 可能被其他进程占用"); } else if (ret == AVERROR(ENOMEM)) { AV_LOGGER_ERROR("内存不足 - 无法分配编码器资源"); } return static_cast(ret); } AV_LOGGER_INFOF("编码器打开成功: {}", videoParams_.codecName); return ErrorCode::SUCCESS; } ErrorCode VideoEncoder::setupEncoderParams() { codecCtx_->bit_rate = videoParams_.bitRate; codecCtx_->width = videoParams_.width; codecCtx_->height = videoParams_.height; codecCtx_->time_base = {1, videoParams_.fps}; codecCtx_->framerate = {videoParams_.fps, 1}; codecCtx_->gop_size = videoParams_.gopSize; codecCtx_->max_b_frames = videoParams_.maxBFrames; // 设置像素格式 if (isHardwareEncoder_) { AVPixelFormat hwPixFmt = getHardwarePixelFormat(); if (hwPixFmt == AV_PIX_FMT_NONE) { AV_LOGGER_ERRORF("获取硬件像素格式失败,编码器: {}", videoParams_.codecName); return ErrorCode::NOT_SUPPORTED; } codecCtx_->pix_fmt = hwPixFmt; AV_LOGGER_INFOF("设置硬件编码器像素格式: {} ({})", static_cast(hwPixFmt), av_get_pix_fmt_name(hwPixFmt)); } else { codecCtx_->pix_fmt = videoParams_.pixelFormat; AV_LOGGER_INFOF("设置软件编码器像素格式: {} ({})", static_cast(videoParams_.pixelFormat), av_get_pix_fmt_name(videoParams_.pixelFormat)); } // 针对不同编码器设置特定参数 if (videoParams_.codecName == "h264_nvenc") { AV_LOGGER_INFO("设置NVENC编码器参数..."); // NVENC 特定参数 - 使用更保守的设置 int ret; ret = av_opt_set(codecCtx_->priv_data, "preset", "medium", 0); AV_LOGGER_INFOF("Set preset=medium: {}", ret == 0 ? "success" : "failed"); ret = av_opt_set(codecCtx_->priv_data, "profile", "main", 0); AV_LOGGER_INFOF("Set profile=main: {}", ret == 0 ? "success" : "failed"); ret = av_opt_set(codecCtx_->priv_data, "rc", "vbr", 0); AV_LOGGER_INFOF("Set rc=vbr: {}", ret == 0 ? "success" : "failed"); ret = av_opt_set_int(codecCtx_->priv_data, "surfaces", 16, 0); AV_LOGGER_INFOF("Set surfaces=16: {}", ret == 0 ? "success" : "failed"); ret = av_opt_set_int(codecCtx_->priv_data, "delay", 0, 0); AV_LOGGER_INFOF("Set delay=0: {}", ret == 0 ? "success" : "failed"); if (videoParams_.lowLatency) { AV_LOGGER_INFO("启用低延迟模式"); ret = av_opt_set(codecCtx_->priv_data, "preset", "fast", 0); AV_LOGGER_INFOF("Set preset=fast: {}", ret == 0 ? "success" : "failed"); ret = av_opt_set(codecCtx_->priv_data, "tune", "ll", 0); AV_LOGGER_INFOF("Set tune=ll: {}", ret == 0 ? "success" : "failed"); } } else if (videoParams_.codecName == "h264_qsv") { // QSV 特定参数 av_opt_set(codecCtx_->priv_data, "preset", "fast", 0); av_opt_set(codecCtx_->priv_data, "profile", "high", 0); if (videoParams_.lowLatency) { av_opt_set(codecCtx_->priv_data, "preset", "veryfast", 0); } } else if (videoParams_.codecName == "h264_amf") { // AMF 特定参数 av_opt_set(codecCtx_->priv_data, "quality", "speed", 0); av_opt_set(codecCtx_->priv_data, "profile", "high", 0); if (videoParams_.lowLatency) { av_opt_set(codecCtx_->priv_data, "usage", "lowlatency", 0); } } else { // 软件编码器参数 if (!videoParams_.preset.empty()) { av_opt_set(codecCtx_->priv_data, "preset", videoParams_.preset.c_str(), 0); } if (!videoParams_.tune.empty()) { av_opt_set(codecCtx_->priv_data, "tune", videoParams_.tune.c_str(), 0); } if (videoParams_.lowLatency) { av_opt_set(codecCtx_->priv_data, "preset", "ultrafast", 0); av_opt_set(codecCtx_->priv_data, "tune", "zerolatency", 0); } } return ErrorCode::SUCCESS; } ErrorCode VideoEncoder::setupHardwareAcceleration() { isHardwareEncoder_ = true; AVHWDeviceType hwType = getHardwareDeviceType(); if (hwType == AV_HWDEVICE_TYPE_NONE) { AV_LOGGER_ERRORF("不支持的硬件编码器: {}", videoParams_.codecName); return ErrorCode::NOT_SUPPORTED; } AV_LOGGER_INFOF("开始设置硬件加速: 编码器={}, 设备类型={}", videoParams_.codecName, static_cast(hwType)); // 对于CUDA设备,检查可用性 if (hwType == AV_HWDEVICE_TYPE_CUDA) { AV_LOGGER_INFO("检查CUDA设备可用性..."); // 这里可以添加CUDA设备检查逻辑 } // 创建硬件设备上下文 AV_LOGGER_INFO("创建硬件设备上下文..."); int ret = av_hwdevice_ctx_create(&hwDeviceCtx_, hwType, nullptr, nullptr, 0); if (ret < 0) { AV_LOGGER_ERRORF("创建硬件设备上下文失败: {} (编码器: {}, 错误码: {})", ffmpeg_utils::errorToString(ret), videoParams_.codecName, ret); // 特定错误处理 if (ret == AVERROR(ENOENT)) { AV_LOGGER_ERROR("硬件设备不存在或驱动未安装"); if (hwType == AV_HWDEVICE_TYPE_CUDA) { AV_LOGGER_ERROR("请检查NVIDIA驱动和CUDA是否正确安装"); } } else if (ret == AVERROR(EBUSY)) { AV_LOGGER_ERROR("硬件设备正在被其他进程使用"); } else if (ret == AVERROR(EINVAL)) { AV_LOGGER_ERROR("硬件设备参数无效"); } else if (ret == AVERROR(ENOMEM)) { AV_LOGGER_ERROR("内存不足,无法创建硬件设备上下文"); } return static_cast(ret); } AV_LOGGER_INFOF("硬件设备上下文创建成功: {}", videoParams_.codecName); // 设置硬件帧上下文 return setupHardwareFrameContext(); } ErrorCode VideoEncoder::setupHardwareFrameContext() { AVBufferRef* hwFramesRef = av_hwframe_ctx_alloc(hwDeviceCtx_); if (!hwFramesRef) { AV_LOGGER_ERROR("分配硬件帧上下文失败"); return ErrorCode::MEMORY_ALLOC_FAILED; } AVHWFramesContext* framesCtx = reinterpret_cast(hwFramesRef->data); framesCtx->format = getHardwarePixelFormat(); // 设置软件格式 - 统一使用NV12格式,这是大多数硬件编码器的首选格式 framesCtx->sw_format = AV_PIX_FMT_NV12; framesCtx->width = videoParams_.width; framesCtx->height = videoParams_.height; framesCtx->initial_pool_size = 8; // 增加池大小以提高稳定性 AV_LOGGER_INFOF("设置硬件帧上下文: {}x{}, 硬件格式: {}, 软件格式: {}, 池大小: {}", framesCtx->width, framesCtx->height, static_cast(framesCtx->format), static_cast(framesCtx->sw_format), framesCtx->initial_pool_size); int ret = av_hwframe_ctx_init(hwFramesRef); if (ret < 0) { AV_LOGGER_ERRORF("初始化硬件帧上下文失败: {}", ffmpeg_utils::errorToString(ret)); av_buffer_unref(&hwFramesRef); return static_cast(ret); } codecCtx_->hw_frames_ctx = av_buffer_ref(hwFramesRef); av_buffer_unref(&hwFramesRef); AV_LOGGER_INFO("硬件帧上下文初始化成功"); return ErrorCode::SUCCESS; } AVFramePtr VideoEncoder::convertFrame(const AVFramePtr& frame) { if (!frame) { AV_LOGGER_ERROR("输入帧为空"); return nullptr; } // 对于YUV420P格式,直接使用软件编码,避免不必要的格式转换 // 让OpenGL直接处理原始YUV数据进行显示 if (frame->format == AV_PIX_FMT_YUV420P) { // AV_LOGGER_DEBUG("检测到YUV420P格式,直接使用软件编码,避免格式转换"); // 创建一个新的帧来返回 AVFramePtr resultFrame = makeAVFrame(); if (!resultFrame) { AV_LOGGER_ERROR("创建结果帧失败"); return nullptr; } // 复制帧数据 if (av_frame_ref(resultFrame.get(), frame.get()) < 0) { AV_LOGGER_ERROR("复制帧数据失败"); return nullptr; } return resultFrame; } AVPixelFormat targetFormat; if (isHardwareEncoder_) { // 对于硬件编码器,暂时使用软件编码避免格式转换问题 AV_LOGGER_WARNING("硬件编码器检测到,但为避免格式转换问题,使用软件编码"); targetFormat = static_cast(frame->format); // 使用输入格式 } else { targetFormat = videoParams_.pixelFormat; } AV_LOGGER_DEBUGF("帧格式转换: {}x{} format:{} -> {}", frame->width, frame->height, static_cast(frame->format), static_cast(targetFormat)); // 如果格式已经匹配,创建新帧返回 if (frame->format == targetFormat) { // 创建一个新的帧来返回,避免拷贝构造 AVFramePtr resultFrame = makeAVFrame(); if (!resultFrame) { AV_LOGGER_ERROR("创建结果帧失败"); return nullptr; } // 复制帧数据 if (av_frame_ref(resultFrame.get(), frame.get()) < 0) { AV_LOGGER_ERROR("复制帧数据失败"); return nullptr; } return resultFrame; } // 对于其他格式转换需求,仅在必要时进行 AV_LOGGER_WARNING("检测到格式转换需求,建议优化数据流避免不必要的转换"); // 创建转换器 if (!converter_ || converter_->srcFormat_ != static_cast(frame->format) || converter_->dstFormat_ != targetFormat) { AV_LOGGER_DEBUGF("创建新的像素格式转换器: {} -> {}", static_cast(frame->format), static_cast(targetFormat)); converter_ = std::make_unique( static_cast(frame->format), targetFormat); } auto result = converter_->convert(frame); if (!result) { AV_LOGGER_ERRORF("像素格式转换失败: {} -> {}", static_cast(frame->format), static_cast(targetFormat)); } return result; } AVFramePtr VideoEncoder::transferToHardware(const AVFramePtr& frame) { if (!isHardwareEncoder_ || !frame) { // 创建一个新的帧来返回,避免拷贝构造 if (frame) { AVFramePtr resultFrame = makeAVFrame(); if (!resultFrame) { return nullptr; } // 复制帧数据 if (av_frame_ref(resultFrame.get(), frame.get()) < 0) { return nullptr; } return resultFrame; } return nullptr; } // 分配硬件帧 hwFrame_ = makeAVFrame(); if (!hwFrame_) { AV_LOGGER_ERROR("分配硬件帧失败"); return nullptr; } int ret = av_hwframe_get_buffer(codecCtx_->hw_frames_ctx, hwFrame_.get(), 0); if (ret < 0) { AV_LOGGER_ERRORF("获取硬件帧缓冲区失败: {}", ffmpeg_utils::errorToString(ret)); return nullptr; } // 传输数据到硬件 ret = av_hwframe_transfer_data(hwFrame_.get(), frame.get(), 0); if (ret < 0) { AV_LOGGER_ERRORF("传输数据到硬件失败: {}", ffmpeg_utils::errorToString(ret)); return nullptr; } // 复制时间戳等信息 av_frame_copy_props(hwFrame_.get(), frame.get()); return std::move(hwFrame_); } ErrorCode VideoEncoder::encodeFrame(const AVFramePtr& frame, std::vector& packets) { AVFramePtr processedFrame; if (frame) { // 格式转换 auto convertedFrame = convertFrame(frame); if (!convertedFrame) { AV_LOGGER_ERROR("帧格式转换失败"); return ErrorCode::CONVERSION_FAILED; } processedFrame = std::move(convertedFrame); // 硬件传输 auto hwFrame = transferToHardware(processedFrame); if (!hwFrame) { AV_LOGGER_ERROR("硬件传输失败"); return ErrorCode::HARDWARE_ERROR; } processedFrame = std::move(hwFrame); } // 发送帧到编码器 int ret = avcodec_send_frame(codecCtx_.get(), processedFrame ? processedFrame.get() : nullptr); if (ret < 0) { AV_LOGGER_ERRORF("发送帧到编码器失败: {}", ffmpeg_utils::errorToString(ret)); return static_cast(ret); } // 接收编码后的包 return receivePackets(packets); } ErrorCode VideoEncoder::receivePackets(std::vector& packets) { while (true) { AVPacketPtr packet = makeAVPacket(); if (!packet) { return ErrorCode::MEMORY_ALLOC_FAILED; } int ret = avcodec_receive_packet(codecCtx_.get(), packet.get()); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; // 需要更多输入或已结束 } if (ret < 0) { AV_LOGGER_ERRORF("接收编码包失败: {}", ffmpeg_utils::errorToString(ret)); return static_cast(ret); } packets.push_back(std::move(packet)); } return ErrorCode::SUCCESS; } AVHWDeviceType VideoEncoder::getHardwareDeviceType() const { if (videoParams_.codecName == "h264_nvenc") { return AV_HWDEVICE_TYPE_CUDA; } else if (videoParams_.codecName == "h264_qsv") { return AV_HWDEVICE_TYPE_QSV; } else if (videoParams_.codecName == "h264_amf") { return AV_HWDEVICE_TYPE_D3D11VA; } else if (videoParams_.codecName == "h264_videotoolbox") { return AV_HWDEVICE_TYPE_VIDEOTOOLBOX; } return AV_HWDEVICE_TYPE_NONE; } AVPixelFormat VideoEncoder::getHardwarePixelFormat() const { if (videoParams_.codecName == "h264_nvenc") { return AV_PIX_FMT_CUDA; } else if (videoParams_.codecName == "h264_qsv") { return AV_PIX_FMT_QSV; } else if (videoParams_.codecName == "h264_amf") { return AV_PIX_FMT_D3D11; } else if (videoParams_.codecName == "h264_videotoolbox") { return AV_PIX_FMT_VIDEOTOOLBOX; } AV_LOGGER_ERRORF("未知的硬件编码器: {}", videoParams_.codecName); return AV_PIX_FMT_NONE; } std::vector VideoEncoder::getSupportedEncoders() { std::call_once(encodersInitFlag_, findUsableEncoders); return supportedEncoders_; } bool VideoEncoder::isHardwareEncoder(const std::string& codecName) { for (const char* hwEncoder : HARDWARE_ENCODERS) { if (codecName == hwEncoder) { return true; } } return false; } std::string VideoEncoder::getRecommendedEncoder() { auto encoders = getSupportedEncoders(); // 优先选择硬件编码器 for (const char* hwEncoder : HARDWARE_ENCODERS) { if (std::find(encoders.begin(), encoders.end(), hwEncoder) != encoders.end()) { return hwEncoder; } } // 回退到软件编码器 for (const char* swEncoder : SOFTWARE_ENCODERS) { if (std::find(encoders.begin(), encoders.end(), swEncoder) != encoders.end()) { return swEncoder; } } return encoders.empty() ? "" : encoders[0]; } void VideoEncoder::findUsableEncoders() { AV_LOGGER_INFO("查找可用的视频编码器..."); // 测试硬件编码器 for (const char* encoder : HARDWARE_ENCODERS) { if (CodecFactory::isCodecSupported(encoder, CodecType::ENCODER, MediaType::VIDEO)) { supportedEncoders_.emplace_back(encoder); AV_LOGGER_INFOF("找到硬件编码器: {}", encoder); } } // 测试软件编码器 for (const char* encoder : SOFTWARE_ENCODERS) { if (CodecFactory::isCodecSupported(encoder, CodecType::ENCODER, MediaType::VIDEO)) { supportedEncoders_.emplace_back(encoder); AV_LOGGER_INFOF("找到软件编码器: {}", encoder); } } AV_LOGGER_INFOF("总共找到 {} 个可用的视频编码器", supportedEncoders_.size()); } // VideoEncoderFactory 实现 std::unique_ptr VideoEncoderFactory::create(const std::string& codecName) { auto encoder = std::make_unique(); if (!codecName.empty()) { if (!CodecFactory::isCodecSupported(codecName, CodecType::ENCODER, MediaType::VIDEO)) { AV_LOGGER_ERRORF("不支持的编码器: {}", codecName); return nullptr; } } return encoder; } std::unique_ptr VideoEncoderFactory::createBest(bool preferHardware) { std::string codecName; if (preferHardware) { codecName = VideoEncoder::getRecommendedEncoder(); } else { // 优先选择软件编码器 auto encoders = VideoEncoder::getSupportedEncoders(); for (const char* swEncoder : VideoEncoder::SOFTWARE_ENCODERS) { if (std::find(encoders.begin(), encoders.end(), swEncoder) != encoders.end()) { codecName = swEncoder; break; } } } if (codecName.empty()) { AV_LOGGER_ERROR("未找到可用的视频编码器"); return nullptr; } return create(codecName); } } // namespace codec } // namespace av