【音视频】内存与 CPU 优化策略

这个系列文章我们来介绍一位海外工程师如何探索安卓音视频基础技术,对于想要开始学习音视频技术的朋友,这些文章是份不错的入门资料,本篇介绍内存与 CPU 优化策略。

——来自公众号“关键帧Keyframe”的分享

1、内存管理架构速览

av_malloc() → 对齐(32/64 B)→ SIMD 可用
     ↘ av_fast_malloc()  增长时免拷贝
       av_buffer_ref()   引用计数零拷贝

目标对齐 + 复用 + 无拷贝 → 降低 25–40 % 内存带宽

2、核心分配函数对比

函数用途开销适用场景
av_malloc()对齐分配普通缓冲区
av_mallocz()清零分配结构体初始化为 0
av_fast_malloc()可变缓冲极低循环复用缓冲
av_malloc_array()数组安全防止整数溢出
av_buffer_alloc()引用计数池零拷贝共享

3、零拷贝缓冲区模型

AVBufferRef *buf = av_buffer_alloc(size);
AVFrame *f = av_frame_alloc();
f->buf[0] = av_buffer_ref(buf);   // 无 memcpy
// 另一帧共享同一块内存
AVFrame *f2 = av_frame_alloc();
f2->buf[0] = av_buffer_ref(buf);

收益:4K60 转码场景 内存峰值 ↓ 35 %

4、对象池化(Packet/Frame)

// 初始化池
#define POOL_SIZE 64
static AVPacket *pkt_pool[POOL_SIZE];
static AVFrame  *frm_pool[POOL_SIZE];
for (int i = 0; i < POOL_SIZE; ++i) {
    pkt_pool[i] = av_packet_alloc();
    frm_pool[i] = av_frame_alloc();
}
// 使用:原子指针栈弹出/压入
AVPacket *pkt = pkt_pool[idx_top++];

效果:运行时分配 0 次,GC 抖动消失

5、CPU 并行模型

并行级别FFmpeg 标志加速比备注
帧级FF_THREAD_FRAME≈ core 数≥ 1080p 有效
片级FF_THREAD_SLICE1.5–2×与 slice 数正相关
流水线自定义线程队列2–3×I/O ↔ 解码 ↔ 编码重叠
codec_ctx->thread_type = FF_THREAD_FRAME | FF_THREAD_SLICE;
codec_ctx->thread_count = av_cpu_count(); // 物理核

6、硬件加速决策树

是否有 GPU? → NVIDIA?
   ↓            ↓
Intel QSV   → NVENC (p1/p2/p3)
   ↓            ↓
AMD VCE     → Apple VideoToolbox
   ↓
回退 x264 (ultrafast)

一键模板

ffmpeg -hwaccel cuda -c:v h264_nvenc -preset p1 -tune ll

7、SIMD 自动向量化

// 保证对齐 → FFmpeg 自动选择 SIMD
void *buf = av_malloc(size); // 64 B 对齐
// 手动 intrinsics(可选)
#include <immintrin.h>
__m256i a = _mm256_load_si256((__m256i*)buf);

常见加速

  • SSE2/AVX2:运动补偿 ↑ 3×
  • NEON:ARM 色彩转换 ↑ 4×

8、缓存友好访问模式

// 结构体数组(SoA)→ 向量化友好
for (int i = 0; i < n; i += 8) {
    __builtin_prefetch(&y[i + 64]); // 预取
    process(y[i], u[i], v[i]);
}

分块大小:32–64 KB(L2 缓存)最佳

9、上下文重用(避免重复 init)

static AVFormatContext *fmt_ctx = NULL;
static AVCodecContext  *dec_ctx = NULL;

int transcode_chunk(const char *in_url, const char *out_url) {
    if (!fmt_ctx) {  // 仅第一次初始化
        avformat_open_input(&fmt_ctx, in_url, NULL, NULL);
        avcodec_open2(dec_ctx, decoder, NULL);
    }
    // 后续只 seek 0 即可复用
    av_seek_frame(fmt_ctx, -1, 0, AVSEEK_FLAG_BACKWARD);
    ...
}

收益:连续文件批处理 init 耗时 ↓ 90 %

10、超时与中断回调

static int64_t last_activity;

static int interrupt_cb(void *ctx) {
    return (av_gettime() - last_activity) > 5*1000000; // 5 s
}

fmt_ctx->interrupt_callback.callback = interrupt_cb;

防止网络阻塞导致 线程堆积 / 内存泄漏

11、性能监控埋点

typedef struct {
    int64_t start;
    int64_t decode;
    int64_t encode;
    int frames;
} Perf;

Perf p = {0};
p.start = av_gettime();
...
p.decode = av_gettime() - p.start;

上报 Prometheus → Grafana 实时看板

12、目标指标对照表

指标目标手段
内存峰值vs 软件 ↓ 40 %零拷贝 + 池化
转码速度≥ 2× 实时帧级并行 + NVENC
CPU 占用< 80 % / 核动态线程 + 回退
缓存未命中< 5 %SoA + 预取
上下文切换最小无锁队列

13、一行命令看效果

ffmpeg -thread_queue_size 512 -i input.mp4 \
       -c:v h264_nvenc -preset p1 -tune ll \
       -c:a copy -max_muxing_queue_size 1024 \
       -f mp4 -movflags faststart output.mp4

实测:4K60 → CPU 从 **380 % ↓ 45 %**,功耗 ↓ 62 W

14. 总结与路线图

  1. 对齐分配 → 解锁 SIMD
  2. 引用计数池 → 零拷贝 & 无运行时分配
  3. 帧/片/流水线并行 → 吃满多核
  4. 硬件加速 → 功耗与延迟双降
  5. 监控→调优→验证闭环 → 长期保持最优

学习和提升音视频开发技术,推荐你加入我们的知识星球:【关键帧的音视频开发圈】

【音视频】内存与 CPU 优化策略

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论