zhuizhu 8 months ago
parent
commit
0ff6d7458d

+ 3 - 3
AV/.xmake/windows/x64/cache/config

@@ -1,7 +1,7 @@
 {
+    recheck = false,
     options = { },
     mtimes = {
-        ["xmake.lua"] = 1753537297
-    },
-    recheck = false
+        ["xmake.lua"] = 1753538152
+    }
 }

+ 14 - 14
AV/.xmake/windows/x64/cache/detect

@@ -1,13 +1,6 @@
 {
-    find_program_msvc_arch_x64_plat_windows_checktoolcxx = {
-        ["cl.exe"] = [[C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.39.33519\bin\HostX64\x64\cl.exe]]
-    },
-    ["lib.detect.has_flags"] = {
-        ["windows_x64_C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe_19.39.33523_cxx__-nologo_-O2"] = true,
-        ["windows_x64_C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe_19.39.33523_cxx_cxflags_-nologo_/W3"] = true,
-        ["windows_x64_C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe_19.39.33523_cxx_cxflags_-nologo_cl_sourceDependencies"] = true,
-        ["windows_x64_C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe_19.39.33523_cxx_cxflags_-nologo_/utf-8"] = true,
-        ["windows_x64_C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe_19.39.33523_cxx_cxflags_-nologo_-DNDEBUG"] = true
+    find_program_msvc_arch_x64_plat_windows_checktoolld = {
+        ["link.exe"] = [[C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.39.33519\bin\HostX64\x64\link.exe]]
     },
     find_program_msvc_arch_x64_plat_windows_checktoolcc = {
         ["cl.exe"] = [[C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.39.33519\bin\HostX64\x64\cl.exe]]
@@ -15,15 +8,22 @@
     find_program_msvc_arch_x64_plat_windows_checktoolar = {
         ["link.exe"] = [[C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.39.33519\bin\HostX64\x64\link.exe]]
     },
-    find_program_msvc_arch_x64_plat_windows_checktoolld = {
-        ["link.exe"] = [[C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.39.33519\bin\HostX64\x64\link.exe]]
-    },
-    find_programver = {
-        ["C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe"] = "19.39.33523"
+    find_program_msvc_arch_x64_plat_windows_checktoolcxx = {
+        ["cl.exe"] = [[C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.39.33519\bin\HostX64\x64\cl.exe]]
     },
     find_program = {
         ["C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe"] = [[C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.39.33519\bin\HostX64\x64\cl.exe]],
         ["cl.exe"] = [[C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.39.33519\bin\HostX64\x64\cl.exe]],
         nim = false
+    },
+    find_programver = {
+        ["C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe"] = "19.39.33523"
+    },
+    ["lib.detect.has_flags"] = {
+        ["windows_x64_C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe_19.39.33523_cxx_cxflags_-nologo_-DNDEBUG"] = true,
+        ["windows_x64_C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe_19.39.33523_cxx_cxflags_-nologo_/utf-8"] = true,
+        ["windows_x64_C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe_19.39.33523_cxx_cxflags_-nologo_cl_sourceDependencies"] = true,
+        ["windows_x64_C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe_19.39.33523_cxx_cxflags_-nologo_/W3"] = true,
+        ["windows_x64_C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe_19.39.33523_cxx__-nologo_-O2"] = true
     }
 }

+ 9 - 1
AV/.xmake/windows/x64/cache/history

@@ -35,6 +35,14 @@
         "xmake build test_decoder",
         "xmake run test_decoder",
         "xmake build test_decoder",
-        "xmake run test_decoder"
+        "xmake run test_decoder",
+        "xmake build test_audio_encoder",
+        "xmake build test_audio_encoder",
+        "xmake build test_audio_encoder",
+        "xmake build test_audio_encoder",
+        "xmake build test_audio_encoder",
+        "xmake build test_audio_encoder",
+        "xmake build test_audio_encoder",
+        "xmake build test_audio_encoder"
     }
 }

File diff suppressed because it is too large
+ 5 - 77
AV/.xmake/windows/x64/cache/toolchain


+ 3 - 1
AV/AV.pri

@@ -22,7 +22,9 @@ SOURCES += \
 
 # SOURCES += $$PWD/test_basic.cpp
 # SOURCES += $$PWD/test_codec.cpp
-SOURCES += $$PWD/test_decoder.cpp
+# SOURCES += $$PWD/test_decoder.cpp
+SOURCES += $$PWD/test_audio_encoder.cpp
+
 
 
 

+ 14 - 1
AV/code/codec/codec_audio_encoder.cpp

@@ -289,7 +289,20 @@ ErrorCode AudioEncoder::encode(const AVFramePtr& frame, std::vector<AVPacketPtr>
 }
 
 ErrorCode AudioEncoder::finishEncode(std::vector<AVPacketPtr>& packets) {
-    return flush();
+    // 不需要额外的锁,因为调用者已经持有锁
+    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) {

+ 419 - 0
AV/test_audio_encoder.cpp

@@ -0,0 +1,419 @@
+#include "code/codec/codec_audio_encoder.h"
+#include "code/base/logger.h"
+#include "code/base/media_common.h"
+#include <iostream>
+#include <vector>
+#include <memory>
+#include <chrono>
+#include <fstream>
+#include <algorithm>
+#include <cmath>
+
+using namespace av;
+using namespace av::codec;
+
+/**
+ * 音频编码器测试类
+ */
+class AudioEncoderTester {
+public:
+    AudioEncoderTester() {
+        Logger::instance().setLevel(LogLevel::DEBUG);
+        Logger::instance().info("=== 音频编码器测试套件 ===");
+    }
+    
+    /**
+     * 测试基本音频编码功能
+     */
+    bool testBasicAudioEncoding() {
+        Logger::instance().info("[测试] 基本音频编码功能...");
+        
+        try {
+            // 创建音频编码器
+            auto encoder = AudioEncoderFactory::create("aac");
+            if (!encoder) {
+                Logger::instance().error("[失败] 无法创建AAC编码器");
+                return false;
+            }
+            
+            // 设置编码参数
+            AudioEncoderParams params;
+            params.codecName = "aac";
+            params.bitRate = 128000;
+            params.sampleRate = 44100;
+            params.channels = 2;
+            params.channelLayout = AV_CHANNEL_LAYOUT_STEREO;
+            params.sampleFormat = AV_SAMPLE_FMT_FLTP;
+            params.frameSize = 1024;
+            
+            // 打开编码器
+            ErrorCode result = encoder->open(params);
+            if (result != ErrorCode::OK) {
+                Logger::instance().errorf("[失败] 打开编码器失败: {}", static_cast<int>(result));
+                return false;
+            }
+            
+            // 创建测试音频帧
+            AVFramePtr frame = createTestAudioFrame(params);
+            if (!frame) {
+                Logger::instance().error("[失败] 创建测试音频帧失败");
+                return false;
+            }
+            
+            // 编码音频帧
+            std::vector<AVPacketPtr> packets;
+            result = encoder->encode(frame, packets);
+            if (result != ErrorCode::OK) {
+                Logger::instance().errorf("[失败] 编码音频帧失败: {}", static_cast<int>(result));
+                return false;
+            }
+            
+            Logger::instance().infof("[成功] 编码产生了 {} 个数据包", packets.size());
+            
+            // 关闭编码器
+            encoder->close();
+            
+            Logger::instance().info("[成功] 基本音频编码测试通过");
+            return true;
+            
+        } catch (const std::exception& e) {
+            Logger::instance().errorf("[异常] {}", e.what());
+            return false;
+        }
+    }
+    
+    /**
+     * 测试多种音频编码器
+     */
+    bool testMultipleEncoders() {
+        Logger::instance().info("[测试] 多种音频编码器支持...");
+        
+        auto supportedEncoders = AudioEncoder::getSupportedEncoders();
+        Logger::instance().infof("支持的编码器数量: {}", supportedEncoders.size());
+        
+        if (supportedEncoders.empty()) {
+            Logger::instance().warning("[警告] 没有找到支持的音频编码器");
+            return false;
+        }
+        
+        int successCount = 0;
+        // 只测试几个主要的编码器,避免实验性编码器导致的问题
+        std::vector<std::string> testEncoders = {"aac", "libmp3lame", "libopus", "flac"};
+        
+        for (const auto& codecName : testEncoders) {
+            // 检查编码器是否在支持列表中
+            if (std::find(supportedEncoders.begin(), supportedEncoders.end(), codecName) == supportedEncoders.end()) {
+                Logger::instance().infof("跳过不支持的编码器: {}", codecName);
+                continue;
+            }
+            
+            Logger::instance().infof("测试编码器: {}", codecName);
+            
+            try {
+                auto encoder = AudioEncoderFactory::create(codecName);
+                if (!encoder) {
+                    Logger::instance().errorf("  [失败] 无法创建编码器: {}", codecName);
+                    continue;
+                }
+                
+                AudioEncoderParams params;
+                params.codecName = codecName;
+                params.bitRate = 128000;
+                params.sampleRate = 44100;
+                params.channels = 2;
+                params.channelLayout = AV_CHANNEL_LAYOUT_STEREO;
+                params.sampleFormat = AV_SAMPLE_FMT_FLTP;
+                
+                ErrorCode result = encoder->open(params);
+                if (result == ErrorCode::OK) {
+                    Logger::instance().infof("  [成功] {} 编码器打开成功", codecName);
+                    successCount++;
+                } else {
+                    Logger::instance().errorf("  [失败] {} 编码器打开失败: {}", codecName, static_cast<int>(result));
+                }
+                
+                // 确保编码器正确关闭
+                encoder->close();
+                encoder.reset(); // 释放编码器资源
+                
+            } catch (const std::exception& e) {
+                Logger::instance().errorf("  [异常] 测试编码器 {} 时发生异常: {}", codecName, e.what());
+            }
+        }
+        
+        Logger::instance().infof("成功测试的编码器: {}/{}", successCount, testEncoders.size());
+        return successCount > 0;
+    }
+    
+    /**
+     * 测试音频重采样功能
+     */
+    bool testAudioResampling() {
+        Logger::instance().info("[测试] 音频重采样功能...");
+        
+        try {
+            AudioResampler resampler;
+            
+            // 设置重采样参数:从48kHz立体声转换为44.1kHz立体声
+            AVChannelLayout srcLayout = AV_CHANNEL_LAYOUT_STEREO;
+            AVChannelLayout dstLayout = AV_CHANNEL_LAYOUT_STEREO;
+            
+            bool result = resampler.init(srcLayout, AV_SAMPLE_FMT_FLTP, 48000,
+                                       dstLayout, AV_SAMPLE_FMT_FLTP, 44100);
+            if (!result) {
+                Logger::instance().error("[失败] 初始化重采样器失败");
+                return false;
+            }
+            
+            // 创建测试音频帧
+            AudioEncoderParams params;
+            params.sampleRate = 48000;
+            params.channels = 2;
+            params.sampleFormat = AV_SAMPLE_FMT_FLTP;
+            
+            AVFramePtr srcFrame = createTestAudioFrame(params);
+            if (!srcFrame) {
+                Logger::instance().error("[失败] 创建源音频帧失败");
+                return false;
+            }
+            
+            // 执行重采样
+            AVFramePtr dstFrame = resampler.resample(srcFrame);
+            if (!dstFrame) {
+                Logger::instance().error("[失败] 音频重采样失败");
+                return false;
+            }
+            
+            Logger::instance().infof("[成功] 重采样: {}Hz -> {}Hz", srcFrame->sample_rate, dstFrame->sample_rate);
+            Logger::instance().infof("[成功] 样本数: {} -> {}", srcFrame->nb_samples, dstFrame->nb_samples);
+            
+            return true;
+            
+        } catch (const std::exception& e) {
+            Logger::instance().errorf("[异常] {}", e.what());
+            return false;
+        }
+    }
+    
+    /**
+     * 测试编码器工厂
+     */
+    bool testEncoderFactory() {
+        Logger::instance().info("[测试] 编码器工厂功能...");
+        
+        // 测试创建最佳编码器
+        auto bestEncoder = AudioEncoderFactory::createBest();
+        if (!bestEncoder) {
+            Logger::instance().error("[失败] 无法创建最佳编码器");
+            return false;
+        }
+        Logger::instance().info("[成功] 创建最佳编码器");
+        
+        // 测试创建无损编码器
+        auto losslessEncoder = AudioEncoderFactory::createLossless();
+        if (!losslessEncoder) {
+            Logger::instance().error("[失败] 无法创建无损编码器");
+            return false;
+        }
+        Logger::instance().info("[成功] 创建无损编码器");
+        
+        // 测试推荐编码器
+        std::string recommended = AudioEncoder::getRecommendedEncoder();
+        if (recommended.empty()) {
+            Logger::instance().error("[失败] 无法获取推荐编码器");
+            return false;
+        }
+        Logger::instance().infof("[成功] 推荐编码器: {}", recommended);
+        
+        return true;
+    }
+    
+    /**
+     * 测试编码器状态管理
+     */
+    bool testEncoderStateManagement() {
+        Logger::instance().info("[测试] 编码器状态管理...");
+        
+        try {
+            auto encoder = AudioEncoderFactory::create("aac");
+            if (!encoder) {
+                Logger::instance().error("[失败] 无法创建编码器");
+                return false;
+            }
+            
+            // 测试初始状态
+            if (encoder->getState() != CodecState::IDLE) {
+                Logger::instance().error("[失败] 初始状态不正确");
+                return false;
+            }
+            
+            // 测试打开编码器
+            AudioEncoderParams params;
+            params.codecName = "aac";
+            params.bitRate = 128000;
+            params.sampleRate = 44100;
+            params.channels = 2;
+            
+            ErrorCode result = encoder->open(params);
+            if (result != ErrorCode::OK) {
+                Logger::instance().error("[失败] 打开编码器失败");
+                return false;
+            }
+            
+            if (encoder->getState() != CodecState::OPENED) {
+                Logger::instance().error("[失败] 打开后状态不正确");
+                return false;
+            }
+            
+            // 测试关闭编码器
+            encoder->close();
+            if (encoder->getState() != CodecState::CLOSED) {
+                Logger::instance().error("[失败] 关闭后状态不正确");
+                return false;
+            }
+            
+            Logger::instance().info("[成功] 编码器状态管理测试通过");
+            return true;
+            
+        } catch (const std::exception& e) {
+            Logger::instance().errorf("[异常] {}", e.what());
+            return false;
+        }
+    }
+    
+    /**
+     * 测试错误处理
+     */
+    bool testErrorHandling() {
+        Logger::instance().info("[测试] 错误处理...");
+        
+        try {
+            // 测试无效编码器名称
+            auto encoder = AudioEncoderFactory::create("invalid_codec");
+            if (encoder) {
+                AudioEncoderParams params;
+                params.codecName = "invalid_codec";
+                ErrorCode result = encoder->open(params);
+                if (result == ErrorCode::OK) {
+                    Logger::instance().error("[失败] 应该拒绝无效编码器");
+                    return false;
+                }
+            }
+            
+            // 测试无效参数
+            encoder = AudioEncoderFactory::create("aac");
+            if (encoder) {
+                AudioEncoderParams params;
+                params.codecName = "aac";
+                params.sampleRate = -1; // 无效采样率
+                params.channels = 0;    // 无效声道数
+                
+                ErrorCode result = encoder->open(params);
+                if (result == ErrorCode::OK) {
+                    Logger::instance().error("[失败] 应该拒绝无效参数");
+                    return false;
+                }
+            }
+            
+            Logger::instance().info("[成功] 错误处理测试通过");
+            return true;
+            
+        } catch (const std::exception& e) {
+            Logger::instance().errorf("[异常] {}", e.what());
+            return false;
+        }
+    }
+    
+    /**
+     * 运行所有测试
+     */
+    bool runAllTests() {
+        Logger::instance().info("开始运行音频编码器测试套件...");
+        
+        bool allPassed = true;
+        
+        allPassed &= testBasicAudioEncoding();
+        allPassed &= testMultipleEncoders();
+        allPassed &= testAudioResampling();
+        allPassed &= testEncoderFactory();
+        allPassed &= testEncoderStateManagement();
+        allPassed &= testErrorHandling();
+        
+        Logger::instance().info("=== 测试结果 ===");
+        if (allPassed) {
+            Logger::instance().info("[成功] 所有音频编码器测试通过!");
+        } else {
+            Logger::instance().error("[失败] 部分测试失败!");
+        }
+        
+        return allPassed;
+    }
+    
+private:
+    /**
+     * 创建测试音频帧
+     */
+    AVFramePtr createTestAudioFrame(const AudioEncoderParams& params) {
+        AVFramePtr frame = makeAVFrame();
+        if (!frame) {
+            return nullptr;
+        }
+        
+        frame->format = params.sampleFormat;
+        frame->sample_rate = params.sampleRate;
+        frame->nb_samples = params.frameSize > 0 ? params.frameSize : 1024;
+        
+        // 设置声道布局
+        if (params.channelLayout.nb_channels > 0) {
+            av_channel_layout_copy(&frame->ch_layout, &params.channelLayout);
+        } else {
+            av_channel_layout_default(&frame->ch_layout, params.channels);
+        }
+        
+        // 分配音频缓冲区
+        int ret = av_frame_get_buffer(frame.get(), 0);
+        if (ret < 0) {
+            return nullptr;
+        }
+        
+        // 填充测试数据(简单的正弦波)
+        fillTestAudioData(frame.get());
+        
+        return frame;
+    }
+    
+    /**
+     * 填充测试音频数据
+     */
+    void fillTestAudioData(AVFrame* frame) {
+        if (frame->format == AV_SAMPLE_FMT_FLTP) {
+            // 浮点平面格式
+            for (int ch = 0; ch < frame->ch_layout.nb_channels; ch++) {
+                float* data = reinterpret_cast<float*>(frame->data[ch]);
+                for (int i = 0; i < frame->nb_samples; i++) {
+                    // 生成440Hz正弦波
+                    double t = static_cast<double>(i) / frame->sample_rate;
+                    data[i] = static_cast<float>(0.5 * sin(2.0 * M_PI * 440.0 * t));
+                }
+            }
+        } else if (frame->format == AV_SAMPLE_FMT_S16) {
+            // 16位整数格式
+            int16_t* data = reinterpret_cast<int16_t*>(frame->data[0]);
+            for (int i = 0; i < frame->nb_samples * frame->ch_layout.nb_channels; i++) {
+                double t = static_cast<double>(i / frame->ch_layout.nb_channels) / frame->sample_rate;
+                data[i] = static_cast<int16_t>(16384 * sin(2.0 * M_PI * 440.0 * t));
+            }
+        }
+    }
+};
+
+int main() {
+    try {
+        AudioEncoderTester tester;
+        bool success = tester.runAllTests();
+        return success ? 0 : 1;
+    } catch (const std::exception& e) {
+        Logger::instance().errorf("测试程序异常: {}", e.what());
+        return 1;
+    }
+}

+ 44 - 0
AV/xmake.lua

@@ -185,4 +185,48 @@ target("test_decoder")
         end)
     end
 
+-- 音频编码器测试程序
+target("test_audio_encoder")
+    set_kind("binary")
+    add_files("test_audio_encoder.cpp")
+    add_deps("av_codec")
+    set_targetdir("$(buildir)/bin")
+    
+    -- FFmpeg库链接
+    if is_plat("windows") then
+        add_includedirs("E:/AAA/ffmpeg-7.0.2-full_build-shared/include")
+        add_linkdirs("E:/AAA/ffmpeg-7.0.2-full_build-shared/lib")
+        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
+        add_links("avdevice", "avfilter", "postproc")
+    end
+    
+    -- Windows下复制FFmpeg DLL
+    if is_plat("windows") then
+        after_build(function (target)
+            local ffmpeg_bin = "E:/AAA/ffmpeg-7.0.2-full_build-shared/bin"
+            local target_dir = target:targetdir()
+            
+            -- 复制FFmpeg DLL文件
+            local dlls = {
+                "avcodec-60.dll",
+                "avformat-60.dll", 
+                "avutil-58.dll",
+                "swscale-7.dll",
+                "swresample-4.dll",
+                "avdevice-60.dll",
+                "avfilter-9.dll",
+                "postproc-57.dll"
+            }
+            
+            for _, dll in ipairs(dlls) do
+                local src = path.join(ffmpeg_bin, dll)
+                local dst = path.join(target_dir, dll)
+                if os.exists(src) then
+                    os.cp(src, dst)
+                    print("Copied: " .. dll)
+                end
+            end
+        end)
+    end
+
 

Some files were not shown because too many files changed in this diff