#include "codec_video_decoder.h" #include "../base/logger.h" #include "../base/media_common.h" #include #include #include extern "C" { #include #include #include #include #include } namespace av { namespace codec { // 静态成员初始化 std::vector VideoDecoder::supportedDecoders_; std::once_flag VideoDecoder::decodersInitFlag_; VideoDecoder::VideoDecoder() : AbstractDecoder(MediaType::VIDEO) { AV_LOGGER_DEBUG("创建视频解码器"); } VideoDecoder::~VideoDecoder() { close(); AV_LOGGER_DEBUG("视频解码器已销毁"); } ErrorCode VideoDecoder::initialize(const CodecParams& params) { if (params.type != MediaType::VIDEO) { AV_LOGGER_ERROR("参数类型不是视频"); return ErrorCode::INVALID_PARAMS; } videoParams_ = static_cast(params); if (!validateParams(params)) { return ErrorCode::INVALID_PARAMS; } setState(CodecState::IDLE); AV_LOGGER_INFOF("视频解码器初始化成功: {}", videoParams_.codecName); return ErrorCode::SUCCESS; } ErrorCode VideoDecoder::open(const CodecParams& params) { std::lock_guard lock(decodeMutex_); // 如果提供了参数,先初始化 if (params.type != MediaType::UNKNOWN) { ErrorCode initResult = initialize(params); if (initResult != ErrorCode::SUCCESS) { return initResult; } } if (state_ != CodecState::IDLE) { AV_LOGGER_ERROR("解码器状态无效,无法打开"); return ErrorCode::INVALID_STATE; } ErrorCode result = initDecoder(); if (result != ErrorCode::SUCCESS) { return result; } setState(CodecState::OPENED); AV_LOGGER_INFOF("视频解码器已打开: {} ({}x{})", videoParams_.codecName, codecCtx_->width, codecCtx_->height); return ErrorCode::SUCCESS; } void VideoDecoder::close() { std::lock_guard lock(decodeMutex_); if (state_ == CodecState::IDLE) { return; } // 清理硬件资源 if (hwDeviceCtx_) { av_buffer_unref(&hwDeviceCtx_); hwDeviceCtx_ = nullptr; } hwFrame_.reset(); codecCtx_.reset(); codec_ = nullptr; isHardwareDecoder_ = false; setState(CodecState::IDLE); AV_LOGGER_DEBUG("视频解码器已关闭"); } ErrorCode VideoDecoder::flush() { std::lock_guard lock(decodeMutex_); if (state_ != CodecState::OPENED && state_ != CodecState::RUNNING) { return ErrorCode::INVALID_STATE; } if (codecCtx_) { avcodec_flush_buffers(codecCtx_.get()); } setState(CodecState::OPENED); AV_LOGGER_DEBUG("视频解码器已重置"); return ErrorCode::SUCCESS; } ErrorCode VideoDecoder::reset() { return flush(); } ErrorCode VideoDecoder::decode(const AVPacketPtr& packet, std::vector& frames) { std::lock_guard lock(decodeMutex_); if (state_ != CodecState::OPENED && state_ != CodecState::RUNNING) { return ErrorCode::INVALID_STATE; } setState(CodecState::RUNNING); auto startTime = std::chrono::high_resolution_clock::now(); ErrorCode result = decodeFrame(packet, frames); auto endTime = std::chrono::high_resolution_clock::now(); double processTime = std::chrono::duration(endTime - startTime).count(); updateStats(result == ErrorCode::SUCCESS, processTime, packet ? packet->size : 0); if (frameCallback_) { for (const auto& frame : frames) { frameCallback_(frame); } } return result; } ErrorCode VideoDecoder::finishDecode(std::vector& frames) { return decode(nullptr, frames); // 发送空包来刷新解码器 } bool VideoDecoder::validateParams(const CodecParams& params) { if (params.type != MediaType::VIDEO) { AV_LOGGER_ERROR("参数媒体类型不是视频"); return false; } const auto& videoParams = static_cast(params); if (videoParams.codecName.empty()) { AV_LOGGER_ERROR("解码器名称为空"); return false; } return true; } ErrorCode VideoDecoder::initDecoder() { // 查找解码器 codec_ = avcodec_find_decoder_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 && isHardwareDecoder(videoParams_.codecName)) { ErrorCode result = setupHardwareAcceleration(); if (result != ErrorCode::SUCCESS) { AV_LOGGER_WARNING("硬件加速设置失败,回退到软件解码"); isHardwareDecoder_ = false; // 清理硬件资源 if (hwDeviceCtx_) { av_buffer_unref(&hwDeviceCtx_); hwDeviceCtx_ = nullptr; } } } // 设置解码器参数 ErrorCode result = setupDecoderParams(); if (result != ErrorCode::SUCCESS) { return result; } // 打开解码器前的详细日志 AV_LOGGER_INFOF("准备打开解码器: {}", videoParams_.codecName); AV_LOGGER_INFOF("解码器参数: 线程数: {}, 像素格式: {}", codecCtx_->thread_count, static_cast(codecCtx_->pix_fmt)); if (isHardwareDecoder_) { AV_LOGGER_INFOF("硬件解码器状态: 设备上下文={}", hwDeviceCtx_ ? "已创建" : "未创建"); } // 打开解码器 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 VideoDecoder::setupDecoderParams() { // 设置线程数 if (videoParams_.threadCount > 0) { codecCtx_->thread_count = videoParams_.threadCount; } else { codecCtx_->thread_count = std::thread::hardware_concurrency(); } // 设置像素格式(如果指定) if (videoParams_.pixelFormat != AV_PIX_FMT_NONE) { codecCtx_->pix_fmt = videoParams_.pixelFormat; } // 低延迟设置 if (videoParams_.lowLatency) { codecCtx_->flags |= AV_CODEC_FLAG_LOW_DELAY; codecCtx_->flags2 |= AV_CODEC_FLAG2_FAST; } // 针对不同解码器设置特定参数 if (videoParams_.codecName.find("cuvid") != std::string::npos) { // NVIDIA CUVID 特定参数 if (codecCtx_->priv_data) { av_opt_set_int(codecCtx_->priv_data, "surfaces", 8, 0); if (videoParams_.lowLatency) { av_opt_set_int(codecCtx_->priv_data, "delay", 0, 0); } } } else if (videoParams_.codecName.find("qsv") != std::string::npos) { // Intel QSV 特定参数 if (videoParams_.lowLatency && codecCtx_->priv_data) { av_opt_set(codecCtx_->priv_data, "async_depth", "1", 0); } } return ErrorCode::SUCCESS; } ErrorCode VideoDecoder::setupHardwareAcceleration() { isHardwareDecoder_ = 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)); // 创建硬件设备上下文 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); // 设置硬件设备上下文到解码器 codecCtx_->hw_device_ctx = av_buffer_ref(hwDeviceCtx_); return ErrorCode::SUCCESS; } ErrorCode VideoDecoder::decodeFrame(const AVPacketPtr& packet, std::vector& frames) { // 发送包到解码器 int ret = avcodec_send_packet(codecCtx_.get(), packet ? packet.get() : nullptr); if (ret < 0 && ret != AVERROR_EOF) { AV_LOGGER_ERRORF("发送包到解码器失败: {}", ffmpeg_utils::errorToString(ret)); return static_cast(ret); } // 接收解码后的帧 return receiveFrames(frames); } ErrorCode VideoDecoder::receiveFrames(std::vector& frames) { while (true) { AVFramePtr frame = makeAVFrame(); if (!frame) { return ErrorCode::MEMORY_ALLOC_FAILED; } int ret = avcodec_receive_frame(codecCtx_.get(), frame.get()); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; // 需要更多输入或已结束 } if (ret < 0) { AV_LOGGER_ERRORF("接收解码帧失败: {}", ffmpeg_utils::errorToString(ret)); return static_cast(ret); } // 处理硬件帧 AVFramePtr processedFrame; if (isHardwareDecoder_) { processedFrame = transferFromHardware(std::move(frame)); if (!processedFrame) { AV_LOGGER_ERROR("硬件帧传输失败"); continue; } } else { processedFrame = std::move(frame); } // 格式转换(如果需要) auto convertedFrame = convertFrame(processedFrame); if (convertedFrame) { frames.push_back(std::move(convertedFrame)); } else { frames.push_back(std::move(processedFrame)); } } return ErrorCode::SUCCESS; } AVFramePtr VideoDecoder::convertFrame(const AVFramePtr& frame) { if (!frame) { return nullptr; } // 如果格式已经匹配,直接返回 if (frame->format == videoParams_.pixelFormat) { return nullptr; // 不需要转换,返回nullptr表示使用原帧 } // 创建转换后的帧 AVFramePtr convertedFrame = makeAVFrame(); if (!convertedFrame) { return nullptr; } convertedFrame->format = videoParams_.pixelFormat; convertedFrame->width = frame->width; convertedFrame->height = frame->height; if (av_frame_get_buffer(convertedFrame.get(), 32) < 0) { AV_LOGGER_ERROR("分配转换帧缓冲区失败"); return nullptr; } // 使用 swscale 进行格式转换 SwsContext* swsCtx = sws_getContext( frame->width, frame->height, static_cast(frame->format), convertedFrame->width, convertedFrame->height, videoParams_.pixelFormat, SWS_BILINEAR, nullptr, nullptr, nullptr ); if (!swsCtx) { AV_LOGGER_ERROR("创建像素格式转换上下文失败"); return nullptr; } sws_scale(swsCtx, frame->data, frame->linesize, 0, frame->height, convertedFrame->data, convertedFrame->linesize); sws_freeContext(swsCtx); // 复制时间戳等信息 av_frame_copy_props(convertedFrame.get(), frame.get()); return convertedFrame; } AVFramePtr VideoDecoder::transferFromHardware(AVFramePtr hwFrame) { if (!hwFrame || !isHardwareDecoder_) { return std::move(hwFrame); } // 创建软件帧 AVFramePtr swFrame = makeAVFrame(); if (!swFrame) { return nullptr; } // 从硬件传输到软件 int ret = av_hwframe_transfer_data(swFrame.get(), hwFrame.get(), 0); if (ret < 0) { AV_LOGGER_ERRORF("从硬件传输数据失败: {}", ffmpeg_utils::errorToString(ret)); return nullptr; } // 复制时间戳等信息 av_frame_copy_props(swFrame.get(), hwFrame.get()); return swFrame; } AVHWDeviceType VideoDecoder::getHardwareDeviceType() const { if (videoParams_.codecName.find("cuvid") != std::string::npos) { return AV_HWDEVICE_TYPE_CUDA; } else if (videoParams_.codecName.find("qsv") != std::string::npos) { return AV_HWDEVICE_TYPE_QSV; } else if (videoParams_.codecName.find("d3d11va") != std::string::npos) { return AV_HWDEVICE_TYPE_D3D11VA; } else if (videoParams_.codecName.find("videotoolbox") != std::string::npos) { return AV_HWDEVICE_TYPE_VIDEOTOOLBOX; } return AV_HWDEVICE_TYPE_NONE; } AVPixelFormat VideoDecoder::getHardwarePixelFormat() const { if (videoParams_.codecName.find("cuvid") != std::string::npos) { return AV_PIX_FMT_CUDA; } else if (videoParams_.codecName.find("qsv") != std::string::npos) { return AV_PIX_FMT_QSV; } else if (videoParams_.codecName.find("d3d11va") != std::string::npos) { return AV_PIX_FMT_D3D11; } else if (videoParams_.codecName.find("videotoolbox") != std::string::npos) { return AV_PIX_FMT_VIDEOTOOLBOX; } AV_LOGGER_ERRORF("未知的硬件解码器: {}", videoParams_.codecName); return AV_PIX_FMT_NONE; } void VideoDecoder::updateStats(bool success, double decodeTime, size_t dataSize) { std::lock_guard lock(statsMutex_); if (success) { stats_.decodedFrames++; stats_.totalBytes += dataSize; // 更新平均解码时间 if (stats_.decodedFrames == 1) { stats_.avgDecodeTime = decodeTime; } else { stats_.avgDecodeTime = (stats_.avgDecodeTime * (stats_.decodedFrames - 1) + decodeTime) / stats_.decodedFrames; } } else { stats_.errorCount++; } } VideoDecoder::DecoderStats VideoDecoder::getStats() const { std::lock_guard lock(statsMutex_); return stats_; } void VideoDecoder::resetStats() { std::lock_guard lock(statsMutex_); stats_ = DecoderStats{}; } std::string VideoDecoder::getDecoderName() const { return videoParams_.codecName; } std::vector VideoDecoder::getSupportedDecoders() { std::call_once(decodersInitFlag_, findUsableDecoders); return supportedDecoders_; } bool VideoDecoder::isHardwareDecoder(const std::string& codecName) { for (const char* hwDecoder : HARDWARE_DECODERS) { if (hwDecoder != nullptr && codecName == hwDecoder) { return true; } } return false; } std::string VideoDecoder::getRecommendedDecoder(const std::string& codecName) { auto decoders = getSupportedDecoders(); if (!codecName.empty()) { // 查找指定编解码格式的最佳解码器 std::string baseCodec = codecName; // 优先选择硬件解码器 for (const char* hwDecoder : HARDWARE_DECODERS) { if (hwDecoder != nullptr) { std::string hwDecoderName = hwDecoder; if (hwDecoderName.find(baseCodec) != std::string::npos && std::find(decoders.begin(), decoders.end(), hwDecoderName) != decoders.end()) { return hwDecoderName; } } } // 回退到软件解码器 if (std::find(decoders.begin(), decoders.end(), baseCodec) != decoders.end()) { return baseCodec; } } // 返回第一个可用的硬件解码器 for (const char* hwDecoder : HARDWARE_DECODERS) { if (hwDecoder != nullptr && std::find(decoders.begin(), decoders.end(), hwDecoder) != decoders.end()) { return hwDecoder; } } // 回退到软件解码器 for (const char* swDecoder : SOFTWARE_DECODERS) { if (swDecoder != nullptr && std::find(decoders.begin(), decoders.end(), swDecoder) != decoders.end()) { return swDecoder; } } return decoders.empty() ? "" : decoders[0]; } void VideoDecoder::findUsableDecoders() { AV_LOGGER_INFO("查找可用的视频解码器..."); // 测试硬件解码器 for (const char* decoder : HARDWARE_DECODERS) { if (decoder != nullptr && CodecFactory::isCodecSupported(decoder, CodecType::DECODER, MediaType::VIDEO)) { supportedDecoders_.emplace_back(decoder); AV_LOGGER_INFOF("找到硬件解码器: {}", decoder); } } // 测试软件解码器 for (const char* decoder : SOFTWARE_DECODERS) { if (decoder != nullptr && CodecFactory::isCodecSupported(decoder, CodecType::DECODER, MediaType::VIDEO)) { supportedDecoders_.emplace_back(decoder); AV_LOGGER_INFOF("找到软件解码器: {}", decoder); } } AV_LOGGER_INFOF("总共找到 {} 个可用的视频解码器", supportedDecoders_.size()); } // VideoDecoderFactory 实现 std::unique_ptr VideoDecoder::VideoDecoderFactory::create(const std::string& codecName) { auto decoder = std::make_unique(); if (!codecName.empty()) { if (!CodecFactory::isCodecSupported(codecName, CodecType::DECODER, MediaType::VIDEO)) { AV_LOGGER_ERRORF("不支持的解码器: {}", codecName); return nullptr; } } return decoder; } std::unique_ptr VideoDecoder::VideoDecoderFactory::createBest(bool preferHardware) { std::string codecName; if (preferHardware) { codecName = VideoDecoder::getRecommendedDecoder(); } else { // 优先选择软件解码器 auto decoders = VideoDecoder::getSupportedDecoders(); for (const char* swDecoder : VideoDecoder::SOFTWARE_DECODERS) { if (swDecoder != nullptr && std::find(decoders.begin(), decoders.end(), swDecoder) != decoders.end()) { codecName = swDecoder; break; } } } if (codecName.empty()) { AV_LOGGER_ERROR("未找到可用的视频解码器"); return nullptr; } return create(codecName); } } // namespace codec } // namespace av