| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633 |
- #include "codec_video_decoder.h"
- #include "../base/logger.h"
- #include "../base/media_common.h"
- #include <algorithm>
- #include <sstream>
- #include <thread>
- extern "C" {
- #include <libavcodec/avcodec.h>
- #include <libavutil/hwcontext.h>
- #include <libavutil/pixdesc.h>
- #include <libavutil/opt.h>
- #include <libswscale/swscale.h>
- }
- namespace av {
- namespace codec {
- // 静态成员初始化
- std::vector<std::string> 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_ARGUMENT;
- }
-
- videoParams_ = static_cast<const VideoDecoderParams&>(params);
-
- if (!validateParams(params)) {
- return ErrorCode::INVALID_PARAMS;
- }
-
- setState(CodecState::IDLE);
- AV_LOGGER_INFOF("视频解码器初始化成功: {}", videoParams_.codecName);
-
- return ErrorCode::OK;
- }
- ErrorCode VideoDecoder::open(const CodecParams& params) {
- std::lock_guard<std::mutex> lock(decodeMutex_);
-
- // 如果提供了参数,先初始化
- if (params.type != MediaType::UNKNOWN) {
- ErrorCode initResult = initialize(params);
- if (initResult != ErrorCode::OK) {
- return initResult;
- }
- }
-
- if (state_ != CodecState::IDLE) {
- AV_LOGGER_ERROR("解码器状态无效,无法打开");
- return ErrorCode::INVALID_STATE;
- }
-
- ErrorCode result = initDecoder();
- if (result != ErrorCode::OK) {
- return result;
- }
-
- setState(CodecState::OPENED);
- AV_LOGGER_INFOF("视频解码器已打开: {} ({}x{})",
- videoParams_.codecName,
- codecCtx_->width, codecCtx_->height);
-
- return ErrorCode::OK;
- }
- void VideoDecoder::close() {
- std::lock_guard<std::mutex> 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<std::mutex> 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::OK;
- }
- ErrorCode VideoDecoder::reset() {
- return flush();
- }
- ErrorCode VideoDecoder::decode(const AVPacketPtr& packet, std::vector<AVFramePtr>& frames) {
- std::lock_guard<std::mutex> 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<double, std::milli>(endTime - startTime).count();
-
- updateStats(result == ErrorCode::OK, processTime,
- packet ? packet->size : 0);
-
- if (frameCallback_) {
- for (const auto& frame : frames) {
- frameCallback_(frame);
- }
- }
-
- return result;
- }
- ErrorCode VideoDecoder::finishDecode(std::vector<AVFramePtr>& 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<const VideoDecoderParams&>(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_ARGUMENT;
- }
-
- // 创建解码上下文
- codecCtx_ = makeAVCodecContext(codec_);
- if (!codecCtx_) {
- AV_LOGGER_ERROR("分配解码上下文失败");
- return ErrorCode::OUT_OF_MEMORY;
- }
-
- // 设置硬件加速
- if (videoParams_.hardwareAccel && isHardwareDecoder(videoParams_.codecName)) {
- ErrorCode result = setupHardwareAcceleration();
- if (result != ErrorCode::OK) {
- AV_LOGGER_WARNING("硬件加速设置失败,回退到软件解码");
- isHardwareDecoder_ = false;
-
- // 清理硬件资源
- if (hwDeviceCtx_) {
- av_buffer_unref(&hwDeviceCtx_);
- hwDeviceCtx_ = nullptr;
- }
- }
- }
-
- // 设置解码器参数
- ErrorCode result = setupDecoderParams();
- if (result != ErrorCode::OK) {
- return result;
- }
-
- // 打开解码器前的详细日志
- AV_LOGGER_INFOF("准备打开解码器: {}", videoParams_.codecName);
- AV_LOGGER_INFOF("解码器参数: 线程数: {}, 像素格式: {}",
- codecCtx_->thread_count,
- static_cast<int>(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<ErrorCode>(ret);
- }
-
- AV_LOGGER_INFOF("解码器打开成功: {}", videoParams_.codecName);
-
- return ErrorCode::OK;
- }
- 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::OK;
- }
- 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<int>(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<ErrorCode>(ret);
- }
-
- AV_LOGGER_INFOF("硬件设备上下文创建成功: {}", videoParams_.codecName);
-
- // 设置硬件设备上下文到解码器
- codecCtx_->hw_device_ctx = av_buffer_ref(hwDeviceCtx_);
-
- return ErrorCode::OK;
- }
- ErrorCode VideoDecoder::decodeFrame(const AVPacketPtr& packet, std::vector<AVFramePtr>& 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<ErrorCode>(ret);
- }
-
- // 接收解码后的帧
- return receiveFrames(frames);
- }
- ErrorCode VideoDecoder::receiveFrames(std::vector<AVFramePtr>& frames) {
- while (true) {
- AVFramePtr frame = makeAVFrame();
- if (!frame) {
- return ErrorCode::OUT_OF_MEMORY;
- }
-
- 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<ErrorCode>(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::OK;
- }
- 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<AVPixelFormat>(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<std::mutex> 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<std::mutex> lock(statsMutex_);
- return stats_;
- }
- void VideoDecoder::resetStats() {
- std::lock_guard<std::mutex> lock(statsMutex_);
- stats_ = DecoderStats{};
- }
- std::string VideoDecoder::getDecoderName() const {
- return videoParams_.codecName;
- }
- std::vector<std::string> 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> VideoDecoder::VideoDecoderFactory::create(const std::string& codecName) {
- auto decoder = std::make_unique<VideoDecoder>();
-
- if (!codecName.empty()) {
- if (!CodecFactory::isCodecSupported(codecName, CodecType::DECODER, MediaType::VIDEO)) {
- AV_LOGGER_ERRORF("不支持的解码器: {}", codecName);
- return nullptr;
- }
- }
-
- return decoder;
- }
- std::unique_ptr<VideoDecoder> 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
|