| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223 |
- #include "codec_audio_encoder.h"
- #include "../base/logger.h"
- #include "../base/media_common.h"
- #include <algorithm>
- #include <chrono>
- namespace av {
- namespace codec {
- // 静态成员初始化
- std::vector<std::string> 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<const uint8_t**>(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<AVFramePtr> AudioResampler::flush() {
- std::vector<AVFramePtr> 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<std::mutex> lock(encodeMutex_);
-
- if (state_ != CodecState::IDLE && state_ != CodecState::CLOSED) {
- AV_LOGGER_WARNING("编码器已打开,先关闭再重新打开");
- close();
- }
-
- if (!validateParams(params)) {
- return ErrorCode::INVALID_PARAMS;
- }
-
- audioParams_ = static_cast<const AudioEncoderParams&>(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<std::mutex> 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<std::mutex> 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<ErrorCode>(ret));
- return static_cast<ErrorCode>(ret);
- }
-
- setState(CodecState::OPENED);
- return ErrorCode::SUCCESS;
- }
- ErrorCode AudioEncoder::encode(const AVFramePtr& frame, std::vector<AVPacketPtr>& packets) {
- // 状态检查(使用基类的线程安全方法)
- if (!isOpened()) {
- return ErrorCode::INVALID_STATE;
- }
-
- // 只在处理过程中锁定,缩小锁的粒度
- std::lock_guard<std::mutex> 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<double, std::milli>(endTime - startTime).count();
-
- updateStats(result == ErrorCode::SUCCESS, processTime,
- frame ? frame->nb_samples * audioParams_.channels * av_get_bytes_per_sample(static_cast<AVSampleFormat>(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<AVPacketPtr>& 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<ErrorCode>(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<const AudioEncoderParams&>(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<ErrorCode>(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<AudioResampler>();
- if (!resampler_->init(frame->ch_layout, static_cast<AVSampleFormat>(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<AVPacketPtr>& 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<void*>(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<void*>(processedFrame.get()),
- static_cast<void*>(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<AVPacketPtr>& 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<std::string> 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<AVSampleFormat>(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<AVSampleFormat>(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<void*>(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<const void*>(frameBuffer_.data()),
- static_cast<void*>(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<AudioEncoder> AudioEncoderFactory::create(const std::string& codecName) {
- auto encoder = std::make_unique<AudioEncoder>();
-
- if (!codecName.empty()) {
- if (!CodecFactory::isCodecSupported(codecName, CodecType::ENCODER, MediaType::AUDIO)) {
- AV_LOGGER_ERRORF("不支持的编码器: {}", codecName);
- return nullptr;
- }
- }
-
- return encoder;
- }
- std::unique_ptr<AudioEncoder> AudioEncoderFactory::createBest() {
- std::string codecName = AudioEncoder::getRecommendedEncoder();
-
- if (codecName.empty()) {
- AV_LOGGER_ERROR("未找到可用的音频编码器");
- return nullptr;
- }
-
- return create(codecName);
- }
- std::unique_ptr<AudioEncoder> 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<uintptr_t>(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<AVSampleFormat>(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
|