#include "codec_audio_encoder.h" #include "../base/logger.h" #include "../base/media_common.h" #include #include namespace av { namespace codec { // 静态成员初始化 std::vector AudioEncoder::supportedEncoders_; std::once_flag AudioEncoder::encodersInitFlag_; // AudioResampler 实现 AudioResampler::AudioResampler() : swrCtx_(nullptr) , srcFormat_(AV_SAMPLE_FMT_NONE) , dstFormat_(AV_SAMPLE_FMT_NONE) , srcSampleRate_(0) , dstSampleRate_(0) , dstFrameSize_(0) , initialized_(false) { av_channel_layout_default(&srcLayout_, 0); av_channel_layout_default(&dstLayout_, 0); } AudioResampler::~AudioResampler() { if (swrCtx_) { swr_free(&swrCtx_); } av_channel_layout_uninit(&srcLayout_); av_channel_layout_uninit(&dstLayout_); } bool AudioResampler::init(const AVChannelLayout& srcLayout, AVSampleFormat srcFormat, int srcSampleRate, const AVChannelLayout& dstLayout, AVSampleFormat dstFormat, int dstSampleRate) { if (swrCtx_) { swr_free(&swrCtx_); } av_channel_layout_uninit(&srcLayout_); av_channel_layout_uninit(&dstLayout_); // 复制声道布局 if (av_channel_layout_copy(&srcLayout_, &srcLayout) < 0 || av_channel_layout_copy(&dstLayout_, &dstLayout) < 0) { AV_LOGGER_ERROR("复制声道布局失败"); return false; } srcFormat_ = srcFormat; dstFormat_ = dstFormat; srcSampleRate_ = srcSampleRate; dstSampleRate_ = dstSampleRate; // 创建重采样上下文 int ret = swr_alloc_set_opts2(&swrCtx_, &dstLayout_, dstFormat_, dstSampleRate_, &srcLayout_, srcFormat_, srcSampleRate_, 0, nullptr); if (ret < 0) { AV_LOGGER_ERRORF("创建重采样上下文失败: {}", ffmpeg_utils::errorToString(ret)); return false; } // 初始化重采样器 ret = swr_init(swrCtx_); if (ret < 0) { AV_LOGGER_ERRORF("初始化重采样器失败: {}", ffmpeg_utils::errorToString(ret)); swr_free(&swrCtx_); return false; } // 计算输出帧大小 dstFrameSize_ = av_rescale_rnd(1024, dstSampleRate_, srcSampleRate_, AV_ROUND_UP); // 创建输出帧 dstFrame_ = makeAVFrame(); if (!dstFrame_) { AV_LOGGER_ERROR("分配输出帧失败"); return false; } dstFrame_->format = dstFormat_; dstFrame_->sample_rate = dstSampleRate_; av_channel_layout_copy(&dstFrame_->ch_layout, &dstLayout_); dstFrame_->nb_samples = dstFrameSize_; ret = av_frame_get_buffer(dstFrame_.get(), 0); if (ret < 0) { AV_LOGGER_ERRORF("分配帧缓冲区失败: {}", ffmpeg_utils::errorToString(ret)); return false; } initialized_ = true; return true; } AVFramePtr AudioResampler::resample(const AVFramePtr& srcFrame) { if (!initialized_) { AV_LOGGER_ERROR("AudioResampler not initialized"); return nullptr; } if (!srcFrame) { AV_LOGGER_ERROR("Source frame is null"); return nullptr; } if (!swrCtx_) { AV_LOGGER_ERROR("SwrContext is null"); return nullptr; } if (!dstFrame_) { AV_LOGGER_ERROR("Destination frame is null"); return nullptr; } // 验证源帧的有效性 if (srcFrame->nb_samples <= 0) { AV_LOGGER_ERRORF("Invalid source frame samples: {}", srcFrame->nb_samples); return nullptr; } if (!srcFrame->data[0]) { AV_LOGGER_ERROR("Source frame data is null"); return nullptr; } // 计算输出样本数 int dstSamples = av_rescale_rnd(srcFrame->nb_samples, dstSampleRate_, srcSampleRate_, AV_ROUND_UP); if (dstSamples <= 0) { AV_LOGGER_ERRORF("Invalid calculated destination samples: {}", dstSamples); return nullptr; } AV_LOGGER_DEBUGF("Resampling: src_samples={}, dst_samples={}, src_rate={}, dst_rate={}", srcFrame->nb_samples, dstSamples, srcSampleRate_, dstSampleRate_); // 确保输出帧有足够的空间 if (dstFrame_->nb_samples < dstSamples) { AV_LOGGER_DEBUGF("Reallocating destination frame buffer: {} -> {}", dstFrame_->nb_samples, dstSamples); av_frame_unref(dstFrame_.get()); // 重新设置帧格式信息(av_frame_unref 会清除这些信息) dstFrame_->format = dstFormat_; dstFrame_->sample_rate = dstSampleRate_; int ret = av_channel_layout_copy(&dstFrame_->ch_layout, &dstLayout_); if (ret < 0) { AV_LOGGER_ERRORF("复制声道布局失败: {}", ffmpeg_utils::errorToString(ret)); return nullptr; } dstFrame_->nb_samples = dstSamples; ret = av_frame_get_buffer(dstFrame_.get(), 0); if (ret < 0) { AV_LOGGER_ERRORF("重新分配帧缓冲区失败: {}", ffmpeg_utils::errorToString(ret)); return nullptr; } AV_LOGGER_DEBUGF("Frame buffer reallocated successfully: format={}, rate={}, channels={}, samples={}", dstFrame_->format, dstFrame_->sample_rate, dstFrame_->ch_layout.nb_channels, dstFrame_->nb_samples); } // 验证目标帧的有效性 if (!dstFrame_->data[0]) { AV_LOGGER_ERROR("Destination frame data is null after allocation"); return nullptr; } // 执行重采样 AV_LOGGER_DEBUG("Executing swr_convert..."); int convertedSamples = swr_convert(swrCtx_, dstFrame_->data, dstSamples, const_cast(srcFrame->data), srcFrame->nb_samples); if (convertedSamples < 0) { AV_LOGGER_ERRORF("音频重采样失败: {}", ffmpeg_utils::errorToString(convertedSamples)); return nullptr; } dstFrame_->nb_samples = convertedSamples; // 创建输出帧的副本 AVFramePtr outputFrame = makeAVFrame(); if (!outputFrame) { AV_LOGGER_ERROR("分配输出帧失败"); return nullptr; } // 复制重采样后的数据 outputFrame->format = dstFrame_->format; outputFrame->sample_rate = dstFrame_->sample_rate; av_channel_layout_copy(&outputFrame->ch_layout, &dstFrame_->ch_layout); outputFrame->nb_samples = convertedSamples; int ret = av_frame_get_buffer(outputFrame.get(), 0); if (ret < 0) { AV_LOGGER_ERRORF("分配输出帧缓冲区失败: {}", ffmpeg_utils::errorToString(ret)); return nullptr; } // 复制音频数据 ret = av_frame_copy(outputFrame.get(), dstFrame_.get()); if (ret < 0) { AV_LOGGER_ERRORF("复制帧数据失败: {}", ffmpeg_utils::errorToString(ret)); return nullptr; } // 复制时间戳等信息 av_frame_copy_props(outputFrame.get(), srcFrame.get()); // 调整时间戳 if (srcFrame->pts != AV_NOPTS_VALUE) { outputFrame->pts = av_rescale_q(srcFrame->pts, {1, srcSampleRate_}, {1, dstSampleRate_}); } return outputFrame; } std::vector AudioResampler::flush() { std::vector frames; if (!initialized_) { return frames; } while (true) { AVFramePtr frame = makeAVFrame(); if (!frame) { break; } frame->format = dstFormat_; frame->sample_rate = dstSampleRate_; av_channel_layout_copy(&frame->ch_layout, &dstLayout_); frame->nb_samples = dstFrameSize_; int ret = av_frame_get_buffer(frame.get(), 0); if (ret < 0) { break; } int convertedSamples = swr_convert(swrCtx_, frame->data, dstFrameSize_, nullptr, 0); if (convertedSamples <= 0) { break; } frame->nb_samples = convertedSamples; frames.push_back(std::move(frame)); } return frames; } // AudioEncoder 实现 AudioEncoder::AudioEncoder() : AbstractEncoder(MediaType::AUDIO), bufferedSamples_(0) { AV_LOGGER_DEBUG("创建音频编码器"); } AudioEncoder::~AudioEncoder() { close(); AV_LOGGER_DEBUG("音频编码器已销毁"); } ErrorCode AudioEncoder::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; } audioParams_ = static_cast(params); params_ = params; ErrorCode result = initEncoder(); if (result != ErrorCode::SUCCESS) { close(); return result; } // 初始化帧缓冲区 result = initFrameBuffer(); if (result != ErrorCode::SUCCESS) { close(); return result; } setState(CodecState::OPENED); AV_LOGGER_INFOF("音频编码器已打开: {} ({}Hz, {}ch, {}kbps)", audioParams_.codecName, audioParams_.sampleRate, audioParams_.channels, audioParams_.bitRate / 1000); return ErrorCode::SUCCESS; } void AudioEncoder::close() { std::lock_guard lock(encodeMutex_); if (state_ == CodecState::CLOSED || state_ == CodecState::IDLE) { return; } // 清理资源 resampler_.reset(); convertedFrame_.reset(); // 清理帧缓冲区 clearBuffer(); // 清理编解码上下文 codecCtx_.reset(); codec_ = nullptr; setState(CodecState::CLOSED); AV_LOGGER_DEBUG("音频编码器已关闭"); } ErrorCode AudioEncoder::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 AudioEncoder::encode(const AVFramePtr& frame, std::vector& packets) { // 状态检查(使用基类的线程安全方法) if (!isOpened()) { return ErrorCode::INVALID_STATE; } // 只在处理过程中锁定,缩小锁的粒度 std::lock_guard processLock(encodeMutex_); // 使用StateGuard确保异常安全的状态管理 StateGuard stateGuard(this, CodecState::RUNNING); auto startTime = std::chrono::high_resolution_clock::now(); ErrorCode result = ErrorCode::SUCCESS; if (frame) { // 检查是否需要使用帧缓冲机制 if (codecCtx_->frame_size > 0 && frame->nb_samples != codecCtx_->frame_size) { AV_LOGGER_DEBUGF("使用帧缓冲机制处理大帧: 输入={}, 期望={}", frame->nb_samples, codecCtx_->frame_size); // 将大帧添加到缓冲区 result = addToBuffer(frame); if (result != ErrorCode::SUCCESS) { return result; } // 从缓冲区提取标准大小的帧进行编码 while (bufferedSamples_ >= codecCtx_->frame_size) { AVFramePtr smallFrame = extractFrameFromBuffer(); if (smallFrame) { // 使用move语义明确转移所有权,避免潜在的双重释放 ErrorCode encodeResult = encodeFrame(std::move(smallFrame), packets); if (encodeResult != ErrorCode::SUCCESS) { result = encodeResult; break; } } else { break; } } } else { // 直接编码(帧大小匹配) result = encodeFrame(frame, packets); } } else { // 编码空帧(用于刷新) 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->nb_samples * audioParams_.channels * av_get_bytes_per_sample(static_cast(frame->format)) : 0); if (frameCallback_ && frame) { frameCallback_(frame); } for (const auto& packet : packets) { if (packetCallback_) { packetCallback_(packet); } } // 只有在成功时才提交状态变更 if (result == ErrorCode::SUCCESS) { stateGuard.commit(); } return result; } ErrorCode AudioEncoder::finishEncode(std::vector& packets) { // 不需要额外的锁,因为调用者已经持有锁 if (state_ != CodecState::OPENED && state_ != CodecState::RUNNING) { return ErrorCode::INVALID_STATE; } // 发送空帧来刷新编码器 int ret = avcodec_send_frame(codecCtx_.get(), nullptr); if (ret < 0 && ret != AVERROR_EOF) { AV_LOGGER_ERRORF("刷新编码器失败: {}", ffmpeg_utils::errorToString(ret)); return static_cast(ret); } // 接收剩余的包 return receivePackets(packets); } bool AudioEncoder::validateParams(const CodecParams& params) { if (params.type != MediaType::AUDIO) { AV_LOGGER_ERROR("参数媒体类型不是音频"); return false; } const auto& audioParams = static_cast(params); if (audioParams.sampleRate <= 0) { AV_LOGGER_ERROR("采样率无效"); return false; } if (audioParams.channels <= 0) { AV_LOGGER_ERROR("声道数无效"); return false; } if (audioParams.bitRate <= 0) { AV_LOGGER_ERROR("比特率无效"); return false; } if (audioParams.codecName.empty()) { AV_LOGGER_ERROR("编码器名称为空"); return false; } return true; } ErrorCode AudioEncoder::initEncoder() { // 查找编码器 codec_ = avcodec_find_encoder_by_name(audioParams_.codecName.c_str()); if (!codec_) { AV_LOGGER_ERRORF("未找到编码器: {}", audioParams_.codecName); return ErrorCode::CODEC_NOT_FOUND; } if (codec_->type != AVMEDIA_TYPE_AUDIO) { AV_LOGGER_ERROR("编码器类型不是音频"); return ErrorCode::INVALID_PARAMS; } // 创建编码上下文 codecCtx_ = makeAVCodecContext(codec_); if (!codecCtx_) { AV_LOGGER_ERROR("分配编码上下文失败"); return ErrorCode::MEMORY_ALLOC_FAILED; } // 设置编码器参数 ErrorCode result = setupEncoderParams(); if (result != ErrorCode::SUCCESS) { return result; } // 打开编码器 int ret = avcodec_open2(codecCtx_.get(), codec_, nullptr); if (ret < 0) { AV_LOGGER_ERRORF("打开编码器失败: {}", ffmpeg_utils::errorToString(ret)); return static_cast(ret); } return ErrorCode::SUCCESS; } ErrorCode AudioEncoder::setupEncoderParams() { codecCtx_->bit_rate = audioParams_.bitRate; codecCtx_->sample_rate = audioParams_.sampleRate; // 设置声道布局 ErrorCode result = setupChannelLayout(); if (result != ErrorCode::SUCCESS) { return result; } // 设置采样格式 codecCtx_->sample_fmt = getBestSampleFormat(); // 设置帧大小 if (codec_->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) { codecCtx_->frame_size = audioParams_.frameSize; } // 设置配置文件 if (!audioParams_.profile.empty()) { av_opt_set(codecCtx_->priv_data, "profile", audioParams_.profile.c_str(), 0); } return ErrorCode::SUCCESS; } ErrorCode AudioEncoder::setupChannelLayout() { // 设置声道布局 if (audioParams_.channelLayout.nb_channels > 0) { av_channel_layout_copy(&codecCtx_->ch_layout, &audioParams_.channelLayout); } else { // 根据声道数设置默认布局 av_channel_layout_default(&codecCtx_->ch_layout, audioParams_.channels); } return ErrorCode::SUCCESS; } AVFramePtr AudioEncoder::convertFrame(const AVFramePtr& frame) { if (!frame) { return nullptr; } // 检查是否需要转换 bool needConvert = false; if (frame->format != codecCtx_->sample_fmt) { needConvert = true; } if (frame->sample_rate != codecCtx_->sample_rate) { needConvert = true; } if (av_channel_layout_compare(&frame->ch_layout, &codecCtx_->ch_layout) != 0) { needConvert = true; } if (!needConvert) { // 创建一个新的独立帧副本,避免引用计数问题 AVFramePtr resultFrame = makeAVFrame(); if (!resultFrame) { return nullptr; } // 手动复制帧属性 resultFrame->format = frame->format; resultFrame->sample_rate = frame->sample_rate; resultFrame->nb_samples = frame->nb_samples; resultFrame->pts = frame->pts; int ret = av_channel_layout_copy(&resultFrame->ch_layout, &frame->ch_layout); if (ret < 0) { AV_LOGGER_ERRORF("复制声道布局失败: {}", ffmpeg_utils::errorToString(ret)); return nullptr; } // 分配新的数据缓冲区 ret = av_frame_get_buffer(resultFrame.get(), 0); if (ret < 0) { AV_LOGGER_ERRORF("分配帧缓冲区失败: {}", ffmpeg_utils::errorToString(ret)); return nullptr; } // 复制音频数据 ret = av_frame_copy(resultFrame.get(), frame.get()); if (ret < 0) { AV_LOGGER_ERRORF("复制帧数据失败: {}", ffmpeg_utils::errorToString(ret)); return nullptr; } // 复制帧属性 ret = av_frame_copy_props(resultFrame.get(), frame.get()); if (ret < 0) { AV_LOGGER_ERRORF("复制帧属性失败: {}", ffmpeg_utils::errorToString(ret)); return nullptr; } // 最终验证创建的帧副本 if (!isValidFrame(resultFrame)) { AV_LOGGER_ERROR("创建的帧副本无效"); return nullptr; } AV_LOGGER_DEBUG("创建了不需要转换的帧的独立副本"); return resultFrame; } // 创建重采样器 if (!resampler_) { resampler_ = std::make_unique(); if (!resampler_->init(frame->ch_layout, static_cast(frame->format), frame->sample_rate, codecCtx_->ch_layout, codecCtx_->sample_fmt, codecCtx_->sample_rate)) { AV_LOGGER_ERROR("初始化音频重采样器失败"); resampler_.reset(); // 确保失败时清理 return nullptr; } AV_LOGGER_INFO("音频重采样器初始化成功"); } // 双重检查重采样器状态 if (!resampler_) { AV_LOGGER_ERROR("重采样器为空"); return nullptr; } AV_LOGGER_DEBUGF("开始重采样: format={}, rate={}, channels={}", frame->format, frame->sample_rate, frame->ch_layout.nb_channels); return resampler_->resample(frame); } ErrorCode AudioEncoder::encodeFrame(const AVFramePtr& frame, std::vector& packets) { AVFramePtr processedFrame; if (frame) { // 格式转换 processedFrame = convertFrame(frame); if (!processedFrame) { AV_LOGGER_ERROR("音频帧格式转换失败"); return ErrorCode::CONVERSION_FAILED; } // 调试:输出帧信息 AV_LOGGER_DEBUGF("重采样输出帧信息: format={}, rate={}, channels={}, samples={}", processedFrame->format, processedFrame->sample_rate, processedFrame->ch_layout.nb_channels, processedFrame->nb_samples); // 调试:输出编码器期望的信息 AV_LOGGER_DEBUGF("编码器期望格式: format={}, rate={}, channels={}, frame_size={}", codecCtx_->sample_fmt, codecCtx_->sample_rate, codecCtx_->ch_layout.nb_channels, codecCtx_->frame_size); // 检查帧大小是否匹配 if (codecCtx_->frame_size > 0 && processedFrame->nb_samples != codecCtx_->frame_size) { AV_LOGGER_ERRORF("帧大小不匹配: 输入={}, 编码器期望={}", processedFrame->nb_samples, codecCtx_->frame_size); } // 检查格式是否匹配 if (processedFrame->format != codecCtx_->sample_fmt) { AV_LOGGER_ERRORF("采样格式不匹配: 输入={}, 编码器期望={}", processedFrame->format, codecCtx_->sample_fmt); } // 检查采样率是否匹配 if (processedFrame->sample_rate != codecCtx_->sample_rate) { AV_LOGGER_ERRORF("采样率不匹配: 输入={}, 编码器期望={}", processedFrame->sample_rate, codecCtx_->sample_rate); } // 检查声道数是否匹配 if (processedFrame->ch_layout.nb_channels != codecCtx_->ch_layout.nb_channels) { AV_LOGGER_ERRORF("声道数不匹配: 输入={}, 编码器期望={}", processedFrame->ch_layout.nb_channels, codecCtx_->ch_layout.nb_channels); } } // 验证processedFrame的有效性 if (processedFrame) { // 检查帧数据指针的有效性 if (!processedFrame->data || !processedFrame->data[0]) { AV_LOGGER_ERROR("处理后的帧数据指针无效"); return ErrorCode::INVALID_PARAMS; } // 检查帧大小是否合理 if (processedFrame->nb_samples <= 0 || processedFrame->nb_samples > 100000) { AV_LOGGER_ERRORF("处理后的帧大小异常: {}", processedFrame->nb_samples); return ErrorCode::INVALID_PARAMS; } // 检查声道数是否合理 if (processedFrame->ch_layout.nb_channels <= 0 || processedFrame->ch_layout.nb_channels > 32) { AV_LOGGER_ERRORF("处理后的帧声道数异常: {}", processedFrame->ch_layout.nb_channels); return ErrorCode::INVALID_PARAMS; } AV_LOGGER_DEBUGF("即将发送帧到编码器: samples={}, format={}, rate={}, channels={}, data_ptr={}", processedFrame->nb_samples, processedFrame->format, processedFrame->sample_rate, processedFrame->ch_layout.nb_channels, static_cast(processedFrame->data[0])); } else { AV_LOGGER_DEBUG("发送空帧到编码器(flush)"); } // 最后一次验证:确保编码器和帧都有效 if (!codecCtx_ || !codecCtx_.get()) { AV_LOGGER_ERROR("编码器上下文无效"); return ErrorCode::INVALID_STATE; } if (processedFrame) { // 最终检查:确保帧完全有效 if (!isValidFrame(processedFrame)) { AV_LOGGER_ERROR("检测到无效的帧数据"); return ErrorCode::INVALID_PARAMS; } AV_LOGGER_DEBUG("最终验证通过,帧数据有效"); } // 发送帧到编码器 AV_LOGGER_DEBUG("开始调用avcodec_send_frame..."); // 在调用FFmpeg之前进行最后的安全检查 if (processedFrame) { // 确保AVFrame结构本身的完整性 if (processedFrame.get() == nullptr) { AV_LOGGER_ERROR("严重错误:processedFrame智能指针为null"); return ErrorCode::INVALID_PARAMS; } // 检查AVFrame内部指针是否被破坏 if (!processedFrame->data || !processedFrame->data[0]) { AV_LOGGER_ERROR("严重错误:即将发送的帧数据指针为空"); return ErrorCode::INVALID_PARAMS; } AV_LOGGER_DEBUGF("FFmpeg调用前最终检查通过: frame_ptr={}, data_ptr={}", static_cast(processedFrame.get()), static_cast(processedFrame->data[0])); } int ret = avcodec_send_frame(codecCtx_.get(), processedFrame ? processedFrame.get() : nullptr); AV_LOGGER_DEBUGF("avcodec_send_frame返回: {}", ret); if (ret < 0) { ErrorCode error = AbstractCodec::convertFFmpegError(ret); AV_LOGGER_ERRORF("发送帧到编码器失败: {} ({})", AbstractCodec::getErrorDescription(error), ffmpeg_utils::errorToString(ret)); if (processedFrame) { AV_LOGGER_ERRORF("失败的帧信息: samples={}, format={}, rate={}, channels={}", processedFrame->nb_samples, processedFrame->format, processedFrame->sample_rate, processedFrame->ch_layout.nb_channels); } return error; } // 接收编码后的包 return receivePackets(packets); } ErrorCode AudioEncoder::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) { ErrorCode error = AbstractCodec::convertFFmpegError(ret); AV_LOGGER_ERRORF("接收编码包失败: {} ({})", AbstractCodec::getErrorDescription(error), ffmpeg_utils::errorToString(ret)); return error; } packets.push_back(std::move(packet)); } return ErrorCode::SUCCESS; } AVSampleFormat AudioEncoder::getBestSampleFormat() const { if (!codec_->sample_fmts) { return audioParams_.sampleFormat; } // 首先尝试使用指定的格式 for (const AVSampleFormat* fmt = codec_->sample_fmts; *fmt != AV_SAMPLE_FMT_NONE; fmt++) { if (*fmt == audioParams_.sampleFormat) { return *fmt; } } // 返回第一个支持的格式 return codec_->sample_fmts[0]; } int AudioEncoder::getBestSampleRate() const { if (!codec_->supported_samplerates) { return audioParams_.sampleRate; } // 首先尝试使用指定的采样率 for (const int* rate = codec_->supported_samplerates; *rate != 0; rate++) { if (*rate == audioParams_.sampleRate) { return *rate; } } // 返回第一个支持的采样率 return codec_->supported_samplerates[0]; } std::vector AudioEncoder::getSupportedEncoders() { std::call_once(encodersInitFlag_, findSupportedEncoders); return supportedEncoders_; } std::string AudioEncoder::getRecommendedEncoder() { auto encoders = getSupportedEncoders(); // 优先选择高质量编码器 const char* preferredEncoders[] = {"libfdk_aac", "aac", "libopus", "opus", "libmp3lame", "mp3"}; for (const char* encoder : preferredEncoders) { if (std::find(encoders.begin(), encoders.end(), encoder) != encoders.end()) { return encoder; } } return encoders.empty() ? "" : encoders[0]; } bool AudioEncoder::isSampleFormatSupported(const std::string& codecName, AVSampleFormat format) { const AVCodec* codec = avcodec_find_encoder_by_name(codecName.c_str()); if (!codec || !codec->sample_fmts) { return false; } for (const AVSampleFormat* fmt = codec->sample_fmts; *fmt != AV_SAMPLE_FMT_NONE; fmt++) { if (*fmt == format) { return true; } } return false; } bool AudioEncoder::isSampleRateSupported(const std::string& codecName, int sampleRate) { const AVCodec* codec = avcodec_find_encoder_by_name(codecName.c_str()); if (!codec) { return false; } if (!codec->supported_samplerates) { return true; // 支持所有采样率 } for (const int* rate = codec->supported_samplerates; *rate != 0; rate++) { if (*rate == sampleRate) { return true; } } return false; } bool AudioEncoder::isChannelLayoutSupported(const std::string& codecName, const AVChannelLayout& layout) { const AVCodec* codec = avcodec_find_encoder_by_name(codecName.c_str()); if (!codec) { return false; } if (!codec->ch_layouts) { return true; // 支持所有声道布局 } for (const AVChannelLayout* ch_layout = codec->ch_layouts; ch_layout->nb_channels != 0; ch_layout++) { if (av_channel_layout_compare(ch_layout, &layout) == 0) { return true; } } return false; } void AudioEncoder::findSupportedEncoders() { AV_LOGGER_INFO("查找可用的音频编码器..."); for (const char* encoder : AUDIO_ENCODERS) { if (CodecFactory::isCodecSupported(encoder, CodecType::ENCODER, MediaType::AUDIO)) { supportedEncoders_.emplace_back(encoder); AV_LOGGER_INFOF("找到音频编码器: {}", encoder); } } AV_LOGGER_INFOF("总共找到 {} 个可用的音频编码器", supportedEncoders_.size()); } // 帧缓冲和拆分方法实现 ErrorCode AudioEncoder::initFrameBuffer() { if (!codecCtx_ || codecCtx_->frame_size <= 0) { return ErrorCode::SUCCESS; // 不需要缓冲区 } // 初始化临时帧 tempFrame_ = makeAVFrame(); if (!tempFrame_) { AV_LOGGER_ERROR("分配临时帧失败"); return ErrorCode::MEMORY_ALLOC_FAILED; } // 设置临时帧格式 tempFrame_->format = codecCtx_->sample_fmt; tempFrame_->sample_rate = codecCtx_->sample_rate; av_channel_layout_copy(&tempFrame_->ch_layout, &codecCtx_->ch_layout); tempFrame_->nb_samples = codecCtx_->frame_size; // 分配临时帧缓冲区 int ret = av_frame_get_buffer(tempFrame_.get(), 0); if (ret < 0) { AV_LOGGER_ERRORF("分配临时帧缓冲区失败: {}", ffmpeg_utils::errorToString(ret)); return ErrorCode::MEMORY_ALLOC_FAILED; } // 计算缓冲区大小(支持最大帧大小的数据) int bytesPerSample = av_get_bytes_per_sample(codecCtx_->sample_fmt); int maxBufferSize = codecCtx_->frame_size * codecCtx_->ch_layout.nb_channels * bytesPerSample * 100; // 支持100倍大小 frameBuffer_.reserve(maxBufferSize); bufferedSamples_ = 0; AV_LOGGER_DEBUGF("帧缓冲初始化完成: frame_size={}, channels={}, format={}, buffer_capacity={}", codecCtx_->frame_size, codecCtx_->ch_layout.nb_channels, codecCtx_->sample_fmt, maxBufferSize); return ErrorCode::SUCCESS; } ErrorCode AudioEncoder::addToBuffer(const AVFramePtr& frame) { if (!frame || !frame->data[0]) { return ErrorCode::INVALID_PARAMS; } // 计算数据大小 int bytesPerSample = av_get_bytes_per_sample(static_cast(frame->format)); int channels = frame->ch_layout.nb_channels; int frameDataSize = frame->nb_samples * channels * bytesPerSample; AV_LOGGER_DEBUGF("添加到缓冲区: samples={}, bytes={}, buffered_samples={}", frame->nb_samples, frameDataSize, bufferedSamples_); // 检查缓冲区容量 if (frameBuffer_.size() + frameDataSize > frameBuffer_.capacity()) { AV_LOGGER_ERROR("缓冲区容量不足"); return ErrorCode::MEMORY_ALLOC_FAILED; } // 将音频数据添加到缓冲区 // 注意:这里假设音频格式是交错的(interleaved),对于平面(planar)格式需要特殊处理 if (av_sample_fmt_is_planar(static_cast(frame->format))) { AV_LOGGER_ERROR("暂不支持平面音频格式的缓冲处理"); return ErrorCode::NOT_SUPPORTED; } const uint8_t* srcData = frame->data[0]; frameBuffer_.insert(frameBuffer_.end(), srcData, srcData + frameDataSize); bufferedSamples_ += frame->nb_samples; AV_LOGGER_DEBUGF("缓冲区更新: total_samples={}, buffer_size={}", bufferedSamples_, frameBuffer_.size()); return ErrorCode::SUCCESS; } AVFramePtr AudioEncoder::extractFrameFromBuffer() { if (!tempFrame_ || bufferedSamples_ < codecCtx_->frame_size) { return nullptr; } int bytesPerSample = av_get_bytes_per_sample(codecCtx_->sample_fmt); int channels = codecCtx_->ch_layout.nb_channels; int frameDataSize = codecCtx_->frame_size * channels * bytesPerSample; if (frameBuffer_.size() < frameDataSize) { AV_LOGGER_ERROR("缓冲区数据不足"); return nullptr; } // 创建输出帧(手动设置格式信息) AVFramePtr outputFrame = makeAVFrame(); if (!outputFrame) { return nullptr; } // 手动设置帧格式信息(避免使用av_frame_ref导致缓冲区共享) outputFrame->format = codecCtx_->sample_fmt; outputFrame->sample_rate = codecCtx_->sample_rate; int ret = av_channel_layout_copy(&outputFrame->ch_layout, &codecCtx_->ch_layout); if (ret < 0) { AV_LOGGER_ERRORF("复制声道布局失败: {}", ffmpeg_utils::errorToString(ret)); return nullptr; } outputFrame->nb_samples = codecCtx_->frame_size; // 分配新的缓冲区 ret = av_frame_get_buffer(outputFrame.get(), 0); if (ret < 0) { AV_LOGGER_ERRORF("分配输出帧缓冲区失败: {}", ffmpeg_utils::errorToString(ret)); return nullptr; } // 验证分配的缓冲区是否有效 if (!outputFrame->data || !outputFrame->data[0]) { AV_LOGGER_ERROR("分配的帧缓冲区无效"); return nullptr; } AV_LOGGER_DEBUGF("成功分配帧缓冲区: format={}, samples={}, channels={}, data_ptr={}", outputFrame->format, outputFrame->nb_samples, outputFrame->ch_layout.nb_channels, static_cast(outputFrame->data[0])); // 安全检查:确保数据足够 if (frameBuffer_.size() < frameDataSize || !outputFrame->data[0]) { AV_LOGGER_ERROR("数据复制前检查失败"); return nullptr; } // 复制数据 AV_LOGGER_DEBUGF("准备复制音频数据: src_ptr={}, dst_ptr={}, size={}", static_cast(frameBuffer_.data()), static_cast(outputFrame->data[0]), frameDataSize); // 验证源和目标指针的有效性 if (!frameBuffer_.data() || !outputFrame->data[0]) { AV_LOGGER_ERROR("内存复制:源或目标指针无效"); return nullptr; } memcpy(outputFrame->data[0], frameBuffer_.data(), frameDataSize); AV_LOGGER_DEBUG("音频数据复制完成"); // 设置时间戳(简化处理) outputFrame->pts = AV_NOPTS_VALUE; // 最终验证帧的完整性 if (!isValidFrame(outputFrame)) { AV_LOGGER_ERROR("提取的帧无效,丢弃"); return nullptr; } // 安全检查:确保缓冲区操作安全 if (frameDataSize > frameBuffer_.size()) { AV_LOGGER_ERROR("缓冲区数据不足,无法移除"); return nullptr; } // 从缓冲区移除已使用的数据 frameBuffer_.erase(frameBuffer_.begin(), frameBuffer_.begin() + frameDataSize); bufferedSamples_ -= codecCtx_->frame_size; AV_LOGGER_DEBUGF("从缓冲区提取帧: samples={}, remaining_samples={}, remaining_bytes={}", codecCtx_->frame_size, bufferedSamples_, frameBuffer_.size()); // 再次验证帧的有效性(防御性编程) if (!outputFrame->data[0]) { AV_LOGGER_ERROR("严重错误:帧数据在返回前变为空指针"); return nullptr; } return outputFrame; } void AudioEncoder::clearBuffer() { frameBuffer_.clear(); bufferedSamples_ = 0; tempFrame_.reset(); AV_LOGGER_DEBUG("帧缓冲区已清除"); } // AudioEncoderFactory 实现 std::unique_ptr AudioEncoderFactory::create(const std::string& codecName) { auto encoder = std::make_unique(); if (!codecName.empty()) { if (!CodecFactory::isCodecSupported(codecName, CodecType::ENCODER, MediaType::AUDIO)) { AV_LOGGER_ERRORF("不支持的编码器: {}", codecName); return nullptr; } } return encoder; } std::unique_ptr AudioEncoderFactory::createBest() { std::string codecName = AudioEncoder::getRecommendedEncoder(); if (codecName.empty()) { AV_LOGGER_ERROR("未找到可用的音频编码器"); return nullptr; } return create(codecName); } std::unique_ptr AudioEncoderFactory::createLossless() { auto encoders = AudioEncoder::getSupportedEncoders(); // 优先选择无损编码器 const char* losslessEncoders[] = {"flac", "pcm_s24le", "pcm_s16le"}; for (const char* encoder : losslessEncoders) { if (std::find(encoders.begin(), encoders.end(), encoder) != encoders.end()) { return create(encoder); } } AV_LOGGER_WARNING("未找到无损音频编码器,使用默认编码器"); return createBest(); } // 帧验证工具实现 bool AudioEncoder::isValidFrame(const AVFramePtr& frame) { return isValidFramePointer(frame.get()); } bool AudioEncoder::isValidFramePointer(const AVFrame* frame) { if (!frame) { return false; } // 检查基本属性 if (frame->nb_samples <= 0) { AV_LOGGER_ERROR("帧样本数无效"); return false; } if (frame->format < 0) { AV_LOGGER_ERROR("帧格式无效"); return false; } if (frame->sample_rate <= 0) { AV_LOGGER_ERROR("帧采样率无效"); return false; } if (frame->ch_layout.nb_channels <= 0) { AV_LOGGER_ERROR("帧声道数无效"); return false; } // 检查数据指针 if (!frame->data[0]) { AV_LOGGER_ERROR("帧数据指针为空"); return false; } // 通用的指针有效性检查 uintptr_t ptr = reinterpret_cast(frame->data[0]); // 检查常见的无效指针模式 if (ptr == 0) { AV_LOGGER_ERROR("帧数据指针为NULL"); return false; } if (ptr == UINTPTR_MAX || ptr == (UINTPTR_MAX - 1)) { AV_LOGGER_ERRORF("帧数据指针为无效值: 0x{:x}", ptr); return false; } // 检查是否在合理的地址范围内(避免空指针附近的地址) if (ptr < 0x1000) { AV_LOGGER_ERRORF("帧数据指针在低地址空间: 0x{:x}", ptr); return false; } // 在64位系统上,检查是否在用户空间范围内 #if defined(_WIN64) || defined(__x86_64__) || defined(__aarch64__) if (ptr > 0x7FFFFFFFFFFF) { // 用户空间上限 AV_LOGGER_ERRORF("帧数据指针超出用户空间: 0x{:x}", ptr); return false; } #endif // 检查linesize是否合理 if (frame->linesize[0] <= 0) { AV_LOGGER_ERROR("帧linesize无效"); return false; } // 对于音频,检查数据大小是否合理 int expected_size = frame->nb_samples * frame->ch_layout.nb_channels * av_get_bytes_per_sample(static_cast(frame->format)); if (expected_size <= 0 || expected_size > 100 * 1024 * 1024) { // 100MB上限 AV_LOGGER_ERRORF("帧数据大小不合理: {} bytes", expected_size); return false; } return true; } } // namespace codec } // namespace av