用大白话讲清楚音视频性能优化的核心技术
从一个问题开始你有没有遇到过:
• 播放视频时内存越来越大,最后崩溃?
• 视频处理时CPU占用100%,手机发烫?
• 切换清晰度时卡顿好几秒?
今天我们就来聊聊音视频性能优化。
性能优化三板斧 大白话解释性能优化就像"交通管理":
• 内存管理:像停车场管理,车位有限要合理分配
• 多线程:像多车道,让不同任务并行处理
• 缓存策略:像提前备货,减少等待时间
一、内存管理内存优化策略#include <iostream>#include <vector>#include <queue>#include <memory>#include <mutex>// 对象池 - 复用对象避免频繁分配template<typename T>class ObjectPool {private: std::queue<std::unique_ptr<T>> pool_; std::mutex mutex_; size_t max_size_; public: ObjectPool(size_t max_size = 10) : max_size_(max_size) {} // 获取对象 std::unique_ptr<T> acquire() { std::lock_guard<std::mutex> lock(mutex_); if (!pool_.empty()) { auto obj = std::move(pool_.front()); pool_.pop(); std::cout << "♻️ 复用对象,池中剩余: " << pool_.size() << std::endl; return obj; } std::cout << " 创建新对象" << std::endl; return std::make_unique<T>(); } // 归还对象 void release(std::unique_ptr<T> obj) { std::lock_guard<std::mutex> lock(mutex_); if (pool_.size() < max_size_) { pool_.push(std::move(obj)); std::cout << " 对象归还,池中数量: " << pool_.size() << std::endl; } else { std::cout << "️ 池已满,对象销毁" << std::endl; } }};// 视频帧缓冲区struct VideoFrame { std::vector<uint8_t> data; int width = 1920; int height = 1080; int64_t pts = 0; VideoFrame() { // 预分配内存 data.resize(width * height * 3 / 2); // YUV420 } void reset() { pts = 0; // 不释放内存,只重置状态 }};// 环形缓冲区 - 固定大小,循环使用template<typename T, size_t N>class RingBuffer {private: std::array<T, N> buffer_; size_t head_ = 0; size_t tail_ = 0; size_t count_ = 0; std::mutex mutex_; public: bool push(const T& item) { std::lock_guard<std::mutex> lock(mutex_); if (count_ >= N) { return false; // 缓冲区满 } buffer_[tail_] = item; tail_ = (tail_ + 1) % N; count_++; return true; } bool pop(T& item) { std::lock_guard<std::mutex> lock(mutex_); if (count_ == 0) { return false; // 缓冲区空 } item = buffer_[head_]; head_ = (head_ + 1) % N; count_--; return true; } size_t size() const { return count_; } bool empty() const { return count_ == 0; } bool full() const { return count_ >= N; }};// 内存优化演示void demonstrateMemoryOptimization() { std::cout << "=== 内存优化演示 ===" << std::endl; // 1. 对象池演示 std::cout << "\n【对象池】" << std::endl; ObjectPool<VideoFrame> frame_pool(5); std::vector<std::unique_ptr<VideoFrame>> frames; // 获取对象 for (int i = 0; i < 3; i++) { frames.push_back(frame_pool.acquire()); } // 归还对象 for (auto& frame : frames) { frame_pool.release(std::move(frame)); } frames.clear(); // 再次获取(复用) for (int i = 0; i < 3; i++) { frames.push_back(frame_pool.acquire()); } // 2. 环形缓冲区演示 std::cout << "\n【环形缓冲区】" << std::endl; RingBuffer<int, 5> ring; for (int i = 1; i <= 5; i++) { ring.push(i); std::cout << "写入: " << i << ", 缓冲区大小: " << ring.size() << std::endl; } int value; while (ring.pop(value)) { std::cout << "读取: " << value << ", 缓冲区大小: " << ring.size() << std::endl; }}二、多线程优化多线程架构#include <thread>#include <future>#include <condition_variable>#include <functional>// 线程池class ThreadPool {private: std::vector<std::thread> workers_; std::queue<std::function<void()>> tasks_; std::mutex mutex_; std::condition_variable condition_; bool stop_ = false; public: ThreadPool(size_t threads = 4) { for (size_t i = 0; i < threads; i++) { workers_.emplace_back([this] { while (true) { std::function<void()> task; { std::unique_lock<std::mutex> lock(mutex_); condition_.wait(lock, [this] { return stop_ || !tasks_.empty(); }); if (stop_ && tasks_.empty()) return; task = std::move(tasks_.front()); tasks_.pop(); } task(); } }); } std::cout << " 线程池启动,线程数: " << threads << std::endl; } ~ThreadPool() { { std::unique_lock<std::mutex> lock(mutex_); stop_ = true; } condition_.notify_all(); for (auto& worker : workers_) { worker.join(); } std::cout << " 线程池关闭" << std::endl; } template<class F> void enqueue(F&& f) { { std::unique_lock<std::mutex> lock(mutex_); tasks_.emplace(std::forward<F>(f)); } condition_.notify_one(); }};// 音视频处理流水线class AVPipeline {private: ThreadPool decode_pool_{2}; // 解码线程池 ThreadPool process_pool_{2}; // 处理线程池 ThreadPool render_pool_{1}; // 渲染线程池 public: void processFrame(int frame_id) { // 解码任务 decode_pool_.enqueue([this, frame_id] { std::cout << " 解码帧 " << frame_id << " [线程:" << std::this_thread::get_id() << "]" << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(10)); // 解码完成后提交处理任务 process_pool_.enqueue([this, frame_id] { std::cout << " 处理帧 " << frame_id << " [线程:" << std::this_thread::get_id() << "]" << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(5)); // 处理完成后提交渲染任务 render_pool_.enqueue([frame_id] { std::cout << "️ 渲染帧 " << frame_id << " [线程:" << std::this_thread::get_id() << "]" << std::endl; }); }); }); }};void demonstrateMultithreading() { std::cout << "\n=== 多线程优化演示 ===" << std::endl; AVPipeline pipeline; // 提交多个帧处理任务 for (int i = 1; i <= 5; i++) { pipeline.processFrame(i); } // 等待处理完成 std::this_thread::sleep_for(std::chrono::milliseconds(500));}三、缓存策略LRU缓存实现#include <unordered_map>#include <list>// LRU缓存template<typename K, typename V>class LRUCache {private: size_t capacity_; std::list<std::pair<K, V>> items_; std::unordered_map<K, typename std::list<std::pair<K, V>>::iterator> cache_; public: LRUCache(size_t capacity) : capacity_(capacity) {} bool get(const K& key, V& value) { auto it = cache_.find(key); if (it == cache_.end()) { std::cout << "❌ 缓存未命中: " << key << std::endl; return false; } // 移到最前面 items_.splice(items_.begin(), items_, it->second); value = it->second->second; std::cout << "✅ 缓存命中: " << key << std::endl; return true; } void put(const K& key, const V& value) { auto it = cache_.find(key); if (it != cache_.end()) { // 更新已存在的项 it->second->second = value; items_.splice(items_.begin(), items_, it->second); return; } // 检查容量 if (items_.size() >= capacity_) { // 删除最久未使用的项 auto last = items_.back(); cache_.erase(last.first); items_.pop_back(); std::cout << "️ 淘汰缓存: " << last.first << std::endl; } // 添加新项 items_.push_front({key, value}); cache_[key] = items_.begin(); std::cout << " 添加缓存: " << key << std::endl; } size_t size() const { return items_.size(); }};void demonstrateCaching() { std::cout << "\n=== 缓存策略演示 ===" << std::endl; LRUCache<std::string, std::string> cache(3); // 添加缓存 cache.put("video_1", "data_1"); cache.put("video_2", "data_2"); cache.put("video_3", "data_3"); // 访问缓存 std::string value; cache.get("video_1", value); // 命中 cache.get("video_4", value); // 未命中 // 添加新项,触发淘汰 cache.put("video_4", "data_4"); // video_2被淘汰 // 验证淘汰 cache.get("video_2", value); // 未命中 cache.get("video_1", value); // 命中}int main() { demonstrateMemoryOptimization(); demonstrateMultithreading(); demonstrateCaching(); std::cout << "\n 性能优化总结:" << std::endl; std::cout << "1. 对象池:减少内存分配开销" << std::endl; std::cout << "2. 环形缓冲:固定内存,循环使用" << std::endl; std::cout << "3. 线程池:复用线程,减少创建开销" << std::endl; std::cout << "4. 流水线:并行处理,提高吞吐量" << std::endl; std::cout << "5. LRU缓存:热点数据快速访问" << std::endl; return 0;}常见误区❌ 误区1:线程越多越快正确理解:
• 线程数应匹配CPU核心数
• 过多线程增加切换开销
• I/O密集型可以多一些
❌ 误区2:缓存越大越好正确理解:
• 缓存占用内存
• 要设置合理上限
• 及时清理过期数据
本文要点回顾• ✨ 内存管理:对象池、环形缓冲、预分配
• ✨ 多线程:线程池、流水线、并行处理
• ✨ 缓存策略:LRU、预加载、分级缓存
下期预告:跨平台开发 - 一套代码支持多个平台
本文为"音视频大白话"系列第35篇
--- 这是「音视频大白话」系列的第35篇 关注我,持续更新音视频开发干货 有问题欢迎评论区讨论 #音视频开发 #C++ #编程学习 #技术分享 #程序员
转载请注明来自海坡下载,本文标题:《音优化(音视频大白话系列高级篇35性能优化)》
京公网安备11000000000001号
京ICP备11000001号
还没有评论,来说两句吧...