睿诚科技协会

Visual C++音视频编解码如何实践?

第一部分:核心概念与基础理论

在开始编码之前,必须理解音视频编解码的基本原理。

visualc音视频编解码技术及实践
(图片来源网络,侵删)

音视频数字化的基础

  • 模拟信号 vs. 数字信号:自然界的声音和图像是连续的模拟信号,计算机只能处理离散的数字信号,需要通过 采样量化 将模拟信号转换为数字信号。
    • 采样:在时间轴上对信号进行“拍照”,单位是赫兹,CD 音质的采样率是 44.1kHz,意味着每秒采样 44,100 次。
    • 量化:在幅度轴上将采样值划分为有限个等级,单位是比特,16-bit 量化意味着每个采样值用 16 个二进制位表示。
  • 原始数据量巨大:一秒钟的 1080p (1920x1080) 24fps 的 YUV420 格式视频,原始数据量约为 1920 * 1080 * 1.5 * 24 ≈ 74.66 Mbps,一段 3 分钟的歌曲(44.1kHz/16-bit/立体声)原始数据量约为 44100 * 2 * 16 * 180 / 8 / 1024 / 1024 ≈ 30.3 MB,如此大的数据量不经过压缩是无法存储和传输的。

编解码的核心:压缩

压缩分为两种:

  • 无损压缩:可以完全、无失真地恢复原始数据,压缩率有限,常用于音频编码(如 FLAC, ALAC)。
  • 有损压缩:通过去除人眼/人耳不敏感的数据来大幅减小文件体积,无法完全恢复原始数据,这是音视频领域的主流技术。
    • 视频压缩:利用 空间冗余(一帧图像内相邻像素相似)和 时间冗余(相邻帧之间内容相似),关键技术包括 变换编码(如 DCT)、量化熵编码(如 Huffman, CAVLC/CABAC)和 运动估计/补偿(处理时间冗余)。
    • 音频压缩:利用 心理声学模型,去除人耳听不到的声音(低于听阈)和被强音掩盖的弱音(掩蔽效应),关键技术包括 离散余弦变换量化熵编码

主流编解码标准

  • 视频
    • H.264/AVC:目前应用最广泛的视频编码标准,在压缩率和计算复杂度之间取得了很好的平衡,广泛应用于蓝光、网络视频(如 YouTube)、视频会议等。
    • H.265/HEVC:H.264 的继任者,压缩率比 H.264 提升约 50%,但编码和解码的复杂度也显著增加,用于 4K/8K 超高清视频流。
    • AV1:由谷歌、Netflix 等公司主导的开源、免版税的视频编码格式,压缩效率媲美 H.265,是未来的重要方向。
  • 音频
    • AAC (Advanced Audio Coding):MP3 的继任者,在相同比特率下音质更好,是目前最主流的音频编码格式(如 iTunes, YouTube, iOS)。
    • Opus:一个极其灵活和高效的音频编解码器,支持从窄带到超宽带的各种比特率和采样率,专为网络实时传输(如 WebRTC, Discord)设计。
    • FLAC:无损音频压缩的代表。

第二部分:Visual C++ 技术栈与关键组件

使用 C++ 进行音视频开发,离不开一些关键的库和框架。

核心解码库

直接编写一个完整的编解码器(如 H.264 解码器)是极其复杂的,通常依赖于现成的底层库。

  • FFmpeg业界事实上的标准,一个集录制、转换、流化音视频文件的开源项目,它包含了几乎所有的音视频编解码器、格式封装器、协议处理器和滤镜。
    • 核心组件
      • libavcodec:提供编解码功能。
      • libavformat:负责音视频文件的封装和解封装。
      • libavutil:提供公共的工具函数,如数据结构、数学运算、哈希等。
      • libswscale:用于图像色彩空间和尺寸的转换。
      • libswresample:用于音频采样率转换和格式重采样。
    • 集成方式:通常使用预编译好的库文件(如 gpllgpl 版本)和头文件,通过 Visual Studio 的项目配置进行链接。

图形渲染库

解码后的原始数据(如 YUV 视频、PCM 音频)需要显示出来。

visualc音视频编解码技术及实践
(图片来源网络,侵删)
  • DirectShow:Windows 平台下的传统多媒体框架,基于 COM 组件,比较复杂,但功能强大且稳定,很多旧的音视频应用仍在使用。
  • Media Foundation (MF)微软推荐的现代多媒体框架,从 Windows Vista 开始引入,是 DirectShow 的替代品,它更易于使用(基于 COM,但有更现代的 C++ 封装),支持硬件加速,并且是 Windows 8/10/11 上处理多媒体的首选。
  • Direct2D / Direct3D:更底层的图形 API,通常用于高性能的游戏和视频播放器渲染,可以实现复杂的视觉效果和硬件加速的图像处理,FFmpeg 解码后的 YUV 帧可以通过 libswscale 转换为 RGB,然后使用 Direct2D 绘制到窗口上。

开发环境

  • Visual Studio:首选的 IDE,建议安装 “使用 C++ 的桌面开发” 工作负载,它包含了 C++ 编译器、Windows SDK 和必要的工具。
  • CMake:一个跨平台的构建工具,对于像 FFmpeg 这样结构复杂的项目,使用 CMake 来管理编译和链接过程是最佳实践。

第三部分:实践步骤 - 以 FFmpeg + DirectShow/MF 为例

下面我们以开发一个简单的视频播放器为例,梳理整个流程。

步骤 1:环境搭建

  1. 安装 Visual Studio:确保安装了 C++ 桌面开发工作负载。
  2. 获取 FFmpeg 库
    • 访问 FFmpeg 官网 下载 Windows 预编译版本。
    • 解压文件,你会得到 bin, include, lib 三个文件夹。
    • bin 目录下的 .dll 文件(如 avcodec-59.dll, avformat-59.dll 等)复制到你的 Visual Studio 项目的输出目录(如 x64/Debug)。
  3. 配置 Visual Studio 项目
    • 创建一个新的 Windows 桌面应用程序 项目。
    • 项目属性 -> C/C++ -> 常规 -> 附加包含目录:添加 FFmpeg 的 include 目录。
    • 项目属性 -> 链接器 -> 常规 -> 附加库目录:添加 FFmpeg 的 lib 目录。
    • 项目属性 -> 链接器 -> 输入 -> 附加依赖项:添加需要链接的库文件,如 avcodec.lib; avformat.lib; avutil.lib; swscale.lib; swresample.lib

步骤 2:使用 FFmpeg 解码视频

  1. 注册所有组件av_register_all() (旧版) 或 avformat_network_init() (新版)。
  2. 打开媒体文件:使用 avformat_open_input() 打开视频文件,并使用 avformat_find_stream_info() 获取流信息。
  3. 查找视频流:遍历所有流,找到类型为 AVMEDIA_TYPE_VIDEO 的流。
  4. 查找解码器:使用 avcodec_find_decoder_by_name()avcodec_find_decoder() 找到对应的解码器。
  5. 打开解码器:使用 avcodec_open2() 打开解码器,并获取其上下文。
  6. 读取和解码数据包
    • 循环调用 av_read_frame() 从文件中读取一个数据包。
    • 如果数据包的类型是我们找到的视频流,则将其送入解码器。
    • 调用 avcodec_send_packet() 发送数据包。
    • 循环调用 avcodec_receive_frame() 接收解码后的原始帧(AVFrame 结构体,通常包含 YUV 数据)。
  7. 释放资源
visualc音视频编解码技术及实践
(图片来源网络,侵删)
分享:
扫描分享到社交APP