常见音视频格式与编解码技术深度解析

音视频格式和编解码技术是多媒体应用的核心组成部分。本文将深入探讨主流的音视频格式、编解码算法原理、容器格式特性,以及如何在实际项目中选择和使用这些技术。

1. 音视频格式基础概念

1.1 编解码器与容器格式

在音视频处理中,需要区分编解码器(Codec)和容器格式(Container):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 音视频流信息结构
typedef struct {
char codec_name[32]; // 编解码器名称
int codec_id; // 编解码器ID
int bitrate; // 比特率
int sample_rate; // 采样率(音频)
int channels; // 声道数(音频)
int width, height; // 分辨率(视频)
double frame_rate; // 帧率(视频)
int64_t duration; // 时长(微秒)
} StreamInfo;

// 容器格式信息
typedef struct {
char format_name[32]; // 格式名称
int num_streams; // 流数量
StreamInfo *streams; // 流信息数组
char metadata[1024]; // 元数据
int64_t file_size; // 文件大小
} ContainerInfo;

// 解析容器格式(简化示例)
int parse_container_format(const char *filename, ContainerInfo *info) {
FILE *file = fopen(filename, "rb");
if (!file) return -1;

// 读取文件头
char header[12];
fread(header, 1, 12, file);

// 识别格式
if (memcmp(header, "RIFF", 4) == 0 && memcmp(header + 8, "WAVE", 4) == 0) {
strcpy(info->format_name, "WAV");
return parse_wav_format(file, info);
} else if (memcmp(header, "ftyp", 4) == 0) {
strcpy(info->format_name, "MP4");
return parse_mp4_format(file, info);
} else if (memcmp(header, "ID3", 3) == 0 || (header[0] == 0xFF && (header[1] & 0xE0) == 0xE0)) {
strcpy(info->format_name, "MP3");
return parse_mp3_format(file, info);
}

fclose(file);
return -1; // 未知格式
}

1.2 压缩原理

音视频压缩基于以下原理:

  1. 冗余消除:去除时间、空间和统计冗余
  2. 感知编码:利用人类感知特性
  3. 熵编码:使用霍夫曼编码、算术编码等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# 简单的霍夫曼编码实现
import heapq
from collections import defaultdict, Counter

class HuffmanNode:
def __init__(self, char=None, freq=0, left=None, right=None):
self.char = char
self.freq = freq
self.left = left
self.right = right

def __lt__(self, other):
return self.freq < other.freq

class HuffmanEncoder:
def __init__(self):
self.codes = {}
self.root = None

def build_tree(self, text):
"""构建霍夫曼树"""
# 统计字符频率
freq_counter = Counter(text)

# 创建优先队列
heap = [HuffmanNode(char, freq) for char, freq in freq_counter.items()]
heapq.heapify(heap)

# 构建霍夫曼树
while len(heap) > 1:
left = heapq.heappop(heap)
right = heapq.heappop(heap)

merged = HuffmanNode(freq=left.freq + right.freq, left=left, right=right)
heapq.heappush(heap, merged)

self.root = heap[0] if heap else None

# 生成编码表
self._generate_codes(self.root, "")

def _generate_codes(self, node, code):
"""生成编码表"""
if node:
if node.char is not None: # 叶子节点
self.codes[node.char] = code if code else "0"
else:
self._generate_codes(node.left, code + "0")
self._generate_codes(node.right, code + "1")

def encode(self, text):
"""编码文本"""
if not self.codes:
self.build_tree(text)

encoded = "".join(self.codes[char] for char in text)
return encoded

def decode(self, encoded_text):
"""解码文本"""
if not self.root:
return ""

decoded = []
current = self.root

for bit in encoded_text:
if bit == "0":
current = current.left
else:
current = current.right

if current.char is not None: # 到达叶子节点
decoded.append(current.char)
current = self.root

return "".join(decoded)

def get_compression_ratio(self, original_text):
"""计算压缩比"""
encoded = self.encode(original_text)
original_bits = len(original_text) * 8 # 假设每字符8位
compressed_bits = len(encoded)

return compressed_bits / original_bits

# 演示霍夫曼编码
if __name__ == "__main__":
encoder = HuffmanEncoder()
text = "this is an example of huffman encoding"

encoded = encoder.encode(text)
decoded = encoder.decode(encoded)
ratio = encoder.get_compression_ratio(text)

print(f"原文: {text}")
print(f"编码: {encoded}")
print(f"解码: {decoded}")
print(f"压缩比: {ratio:.2f}")
print(f"编码表: {encoder.codes}")

2. 主流音频格式与编解码

2.1 PCM(脉冲编码调制)

PCM是最基础的数字音频格式,无压缩:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// PCM格式处理
typedef struct {
uint16_t audio_format; // 音频格式 (1=PCM)
uint16_t num_channels; // 声道数
uint32_t sample_rate; // 采样率
uint32_t byte_rate; // 字节率
uint16_t block_align; // 块对齐
uint16_t bits_per_sample; // 位深度
} PCMFormat;

// WAV文件头结构
typedef struct {
char riff_header[4]; // "RIFF"
uint32_t wav_size; // 文件大小-8
char wave_header[4]; // "WAVE"
char fmt_header[4]; // "fmt "
uint32_t fmt_chunk_size; // fmt块大小
PCMFormat format;
char data_header[4]; // "data"
uint32_t data_bytes; // 数据大小
} WAVHeader;

// 创建WAV文件
int create_wav_file(const char *filename, PCMFormat *format,
int16_t *samples, int num_samples) {
FILE *file = fopen(filename, "wb");
if (!file) return -1;

WAVHeader header;

// 填充头部信息
memcpy(header.riff_header, "RIFF", 4);
memcpy(header.wave_header, "WAVE", 4);
memcpy(header.fmt_header, "fmt ", 4);
memcpy(header.data_header, "data", 4);

header.fmt_chunk_size = sizeof(PCMFormat);
header.format = *format;
header.data_bytes = num_samples * sizeof(int16_t);
header.wav_size = sizeof(WAVHeader) - 8 + header.data_bytes;

// 写入头部
fwrite(&header, sizeof(WAVHeader), 1, file);

// 写入音频数据
fwrite(samples, sizeof(int16_t), num_samples, file);

fclose(file);
return 0;
}

// 读取WAV文件
int read_wav_file(const char *filename, PCMFormat *format,
int16_t **samples, int *num_samples) {
FILE *file = fopen(filename, "rb");
if (!file) return -1;

WAVHeader header;
fread(&header, sizeof(WAVHeader), 1, file);

// 验证格式
if (memcmp(header.riff_header, "RIFF", 4) != 0 ||
memcmp(header.wave_header, "WAVE", 4) != 0) {
fclose(file);
return -1;
}

*format = header.format;
*num_samples = header.data_bytes / sizeof(int16_t);

*samples = (int16_t*)malloc(header.data_bytes);
if (!*samples) {
fclose(file);
return -1;
}

fread(*samples, sizeof(int16_t), *num_samples, file);

fclose(file);
return 0;
}

2.2 MP3(MPEG-1 Audio Layer III)

MP3使用感知音频编码和MDCT变换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// MP3帧头结构
typedef struct {
uint16_t sync; // 同步字 (0xFFE)
uint8_t version; // MPEG版本
uint8_t layer; // 层
uint8_t protection; // CRC保护
uint8_t bitrate_index; // 比特率索引
uint8_t sampling_freq; // 采样频率索引
uint8_t padding; // 填充位
uint8_t private_bit; // 私有位
uint8_t channel_mode; // 声道模式
uint8_t mode_extension; // 模式扩展
uint8_t copyright; // 版权
uint8_t original; // 原创
uint8_t emphasis; // 强调
} MP3FrameHeader;

// MP3比特率表 (kbps)
static const int mp3_bitrates[2][3][15] = {
// MPEG-1
{
{0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448}, // Layer I
{0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384}, // Layer II
{0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320} // Layer III
},
// MPEG-2/2.5
{
{0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256}, // Layer I
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}, // Layer II
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160} // Layer III
}
};

// MP3采样率表 (Hz)
static const int mp3_sample_rates[3][3] = {
{44100, 48000, 32000}, // MPEG-1
{22050, 24000, 16000}, // MPEG-2
{11025, 12000, 8000} // MPEG-2.5
};

// 解析MP3帧头
int parse_mp3_frame_header(uint32_t header_data, MP3FrameHeader *header) {
header->sync = (header_data >> 21) & 0x7FF;
if (header->sync != 0x7FF) return -1; // 无效同步字

header->version = (header_data >> 19) & 0x3;
header->layer = (header_data >> 17) & 0x3;
header->protection = (header_data >> 16) & 0x1;
header->bitrate_index = (header_data >> 12) & 0xF;
header->sampling_freq = (header_data >> 10) & 0x3;
header->padding = (header_data >> 9) & 0x1;
header->private_bit = (header_data >> 8) & 0x1;
header->channel_mode = (header_data >> 6) & 0x3;
header->mode_extension = (header_data >> 4) & 0x3;
header->copyright = (header_data >> 3) & 0x1;
header->original = (header_data >> 2) & 0x1;
header->emphasis = header_data & 0x3;

return 0;
}

// 计算MP3帧长度
int calculate_mp3_frame_length(MP3FrameHeader *header) {
int version_idx = (header->version == 3) ? 0 : 1; // MPEG-1 or MPEG-2/2.5
int layer_idx = 3 - header->layer; // Layer I=0, II=1, III=2

if (header->bitrate_index == 0 || header->bitrate_index == 15) {
return -1; // 无效比特率
}

int bitrate = mp3_bitrates[version_idx][layer_idx][header->bitrate_index];
int sample_rate = mp3_sample_rates[version_idx][header->sampling_freq];

if (header->layer == 1) { // Layer I
return (12 * bitrate * 1000 / sample_rate + header->padding) * 4;
} else { // Layer II & III
int samples_per_frame = (header->layer == 3) ? 1152 : 576; // Layer III : Layer II
if (header->version != 3) samples_per_frame /= 2; // MPEG-2/2.5

return samples_per_frame * bitrate * 1000 / (8 * sample_rate) + header->padding;
}
}

2.3 AAC(Advanced Audio Coding)

AAC是更先进的音频编码格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// AAC配置信息
typedef struct {
uint8_t object_type; // 对象类型
uint8_t sampling_freq_index; // 采样频率索引
uint8_t channel_config; // 声道配置
uint8_t frame_length_flag; // 帧长度标志
uint8_t depends_on_core_coder; // 依赖核心编码器
uint8_t extension_flag; // 扩展标志
} AACConfig;

// AAC采样率表
static const int aac_sample_rates[] = {
96000, 88200, 64000, 48000, 44100, 32000,
24000, 22050, 16000, 12000, 11025, 8000, 7350
};

// 解析AAC配置
int parse_aac_config(uint8_t *config_data, int config_len, AACConfig *config) {
if (config_len < 2) return -1;

uint16_t config_word = (config_data[0] << 8) | config_data[1];

config->object_type = (config_word >> 11) & 0x1F;
config->sampling_freq_index = (config_word >> 7) & 0xF;
config->channel_config = (config_word >> 3) & 0xF;
config->frame_length_flag = (config_word >> 2) & 0x1;
config->depends_on_core_coder = (config_word >> 1) & 0x1;
config->extension_flag = config_word & 0x1;

return 0;
}

// AAC ADTS头结构
typedef struct {
uint16_t sync; // 同步字 (0xFFF)
uint8_t id; // MPEG标识
uint8_t layer; // 层
uint8_t protection_absent; // CRC保护
uint8_t profile; // 配置文件
uint8_t sampling_freq_index; // 采样频率索引
uint8_t private_bit; // 私有位
uint8_t channel_config; // 声道配置
uint8_t original; // 原创
uint8_t home; // 家用
uint8_t copyright_id; // 版权ID
uint8_t copyright_start; // 版权开始
uint16_t frame_length; // 帧长度
uint16_t buffer_fullness; // 缓冲区满度
uint8_t num_raw_blocks; // 原始块数
} ADTSHeader;

// 解析ADTS头
int parse_adts_header(uint8_t *data, ADTSHeader *header) {
if (!data || !header) return -1;

uint64_t header_data = 0;
for (int i = 0; i < 7; i++) {
header_data = (header_data << 8) | data[i];
}

header->sync = (header_data >> 44) & 0xFFF;
if (header->sync != 0xFFF) return -1;

header->id = (header_data >> 43) & 0x1;
header->layer = (header_data >> 41) & 0x3;
header->protection_absent = (header_data >> 40) & 0x1;
header->profile = (header_data >> 38) & 0x3;
header->sampling_freq_index = (header_data >> 34) & 0xF;
header->private_bit = (header_data >> 33) & 0x1;
header->channel_config = (header_data >> 30) & 0x7;
header->original = (header_data >> 29) & 0x1;
header->home = (header_data >> 28) & 0x1;
header->copyright_id = (header_data >> 27) & 0x1;
header->copyright_start = (header_data >> 26) & 0x1;
header->frame_length = (header_data >> 13) & 0x1FFF;
header->buffer_fullness = (header_data >> 2) & 0x7FF;
header->num_raw_blocks = header_data & 0x3;

return 0;
}

2.4 FLAC(Free Lossless Audio Codec)

FLAC是无损音频压缩格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// FLAC流信息
typedef struct {
uint16_t min_block_size; // 最小块大小
uint16_t max_block_size; // 最大块大小
uint32_t min_frame_size; // 最小帧大小
uint32_t max_frame_size; // 最大帧大小
uint32_t sample_rate; // 采样率
uint8_t channels; // 声道数
uint8_t bits_per_sample; // 位深度
uint64_t total_samples; // 总采样数
uint8_t md5_signature[16]; // MD5签名
} FLACStreamInfo;

// FLAC元数据块头
typedef struct {
uint8_t is_last; // 是否最后一个块
uint8_t block_type; // 块类型
uint32_t length; // 块长度
} FLACMetadataBlockHeader;

// 解析FLAC流信息
int parse_flac_streaminfo(uint8_t *data, FLACStreamInfo *info) {
if (!data || !info) return -1;

info->min_block_size = (data[0] << 8) | data[1];
info->max_block_size = (data[2] << 8) | data[3];
info->min_frame_size = (data[4] << 16) | (data[5] << 8) | data[6];
info->max_frame_size = (data[7] << 16) | (data[8] << 8) | data[9];

uint64_t temp = 0;
for (int i = 10; i < 18; i++) {
temp = (temp << 8) | data[i];
}

info->sample_rate = (temp >> 44) & 0xFFFFF;
info->channels = ((temp >> 41) & 0x7) + 1;
info->bits_per_sample = ((temp >> 36) & 0x1F) + 1;
info->total_samples = temp & 0xFFFFFFFFF;

memcpy(info->md5_signature, data + 18, 16);

return 0;
}

// 简单的线性预测编码(LPC)
typedef struct {
double *coefficients; // LPC系数
int order; // 阶数
double *history; // 历史样本
int history_index; // 历史索引
} LPCEncoder;

// 创建LPC编码器
LPCEncoder* create_lpc_encoder(int order) {
LPCEncoder *encoder = (LPCEncoder*)malloc(sizeof(LPCEncoder));
if (!encoder) return NULL;

encoder->order = order;
encoder->coefficients = (double*)calloc(order, sizeof(double));
encoder->history = (double*)calloc(order, sizeof(double));
encoder->history_index = 0;

if (!encoder->coefficients || !encoder->history) {
free(encoder->coefficients);
free(encoder->history);
free(encoder);
return NULL;
}

return encoder;
}

// LPC预测
double lpc_predict(LPCEncoder *encoder) {
double prediction = 0.0;

for (int i = 0; i < encoder->order; i++) {
int idx = (encoder->history_index - i - 1 + encoder->order) % encoder->order;
prediction += encoder->coefficients[i] * encoder->history[idx];
}

return prediction;
}

// 更新LPC历史
void lpc_update_history(LPCEncoder *encoder, double sample) {
encoder->history[encoder->history_index] = sample;
encoder->history_index = (encoder->history_index + 1) % encoder->order;
}

3. 主流视频格式与编解码

3.1 H.264/AVC(Advanced Video Coding)

H.264是目前最广泛使用的视频编码标准:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// H.264 NAL单元头
typedef struct {
uint8_t forbidden_zero_bit; // 禁止位
uint8_t nal_ref_idc; // NAL参考指示
uint8_t nal_unit_type; // NAL单元类型
} NALUnitHeader;

// H.264 NAL单元类型
typedef enum {
NAL_SLICE = 1, // 非IDR片
NAL_DPA = 2, // 数据分割A
NAL_DPB = 3, // 数据分割B
NAL_DPC = 4, // 数据分割C
NAL_IDR_SLICE = 5, // IDR片
NAL_SEI = 6, // 补充增强信息
NAL_SPS = 7, // 序列参数集
NAL_PPS = 8, // 图像参数集
NAL_AUD = 9, // 访问单元分隔符
NAL_END_SEQUENCE = 10, // 序列结束
NAL_END_STREAM = 11, // 流结束
NAL_FILLER_DATA = 12 // 填充数据
} NALUnitType;

// 解析NAL单元头
int parse_nal_unit_header(uint8_t header_byte, NALUnitHeader *header) {
header->forbidden_zero_bit = (header_byte >> 7) & 0x1;
header->nal_ref_idc = (header_byte >> 5) & 0x3;
header->nal_unit_type = header_byte & 0x1F;

if (header->forbidden_zero_bit != 0) {
return -1; // 错误的NAL单元
}

return 0;
}

// H.264序列参数集(SPS)简化结构
typedef struct {
uint8_t profile_idc; // 配置文件IDC
uint8_t constraint_flags; // 约束标志
uint8_t level_idc; // 级别IDC
uint32_t seq_parameter_set_id; // SPS ID
uint32_t chroma_format_idc; // 色度格式
uint32_t bit_depth_luma; // 亮度位深度
uint32_t bit_depth_chroma; // 色度位深度
uint32_t log2_max_frame_num; // 最大帧号对数
uint32_t pic_order_cnt_type; // 图像顺序计数类型
uint32_t pic_width_in_mbs; // 图像宽度(宏块)
uint32_t pic_height_in_mbs; // 图像高度(宏块)
uint8_t frame_mbs_only_flag; // 仅帧宏块标志
} H264SPS;

// 指数哥伦布编码解码
uint32_t decode_exp_golomb_ue(uint8_t **data, int *bit_offset) {
int leading_zeros = 0;

// 计算前导零的数量
while (!get_bit(data, bit_offset)) {
leading_zeros++;
}

if (leading_zeros == 0) {
return 0;
}

// 读取剩余位
uint32_t value = 0;
for (int i = 0; i < leading_zeros; i++) {
value = (value << 1) | get_bit(data, bit_offset);
}

return value + (1 << leading_zeros) - 1;
}

// 获取单个比特
int get_bit(uint8_t **data, int *bit_offset) {
int byte_offset = *bit_offset / 8;
int bit_pos = 7 - (*bit_offset % 8);

int bit = ((*data)[byte_offset] >> bit_pos) & 0x1;
(*bit_offset)++;

return bit;
}

// 宏块预测模式
typedef enum {
INTRA_4x4 = 0, // 4x4帧内预测
INTRA_16x16 = 1, // 16x16帧内预测
INTER_16x16 = 2, // 16x16帧间预测
INTER_16x8 = 3, // 16x8帧间预测
INTER_8x16 = 4, // 8x16帧间预测
INTER_8x8 = 5 // 8x8帧间预测
} MacroblockType;

// 运动向量
typedef struct {
int16_t x, y; // 运动向量分量
} MotionVector;

// 宏块结构
typedef struct {
MacroblockType type; // 宏块类型
MotionVector mv[4]; // 运动向量(最多4个)
int16_t residual[16][16]; // 残差数据
uint8_t qp; // 量化参数
} Macroblock;

3.2 H.265/HEVC(High Efficiency Video Coding)

H.265提供了比H.264更高的压缩效率:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// HEVC NAL单元头
typedef struct {
uint8_t forbidden_zero_bit; // 禁止位
uint8_t nal_unit_type; // NAL单元类型
uint8_t nuh_layer_id; // 层ID
uint8_t nuh_temporal_id; // 时间ID
} HEVCNALUnitHeader;

// HEVC编码单元(CU)
typedef struct {
uint8_t cu_size; // CU大小 (8, 16, 32, 64)
uint8_t prediction_mode; // 预测模式
uint8_t part_mode; // 分割模式
uint8_t intra_pred_mode[4]; // 帧内预测模式
MotionVector mv[2]; // 运动向量
int16_t *coefficients; // 变换系数
} CodingUnit;

// HEVC预测单元(PU)
typedef struct {
uint8_t pu_size; // PU大小
uint8_t merge_flag; // 合并标志
uint8_t merge_idx; // 合并索引
MotionVector mv[2]; // 双向运动向量
uint8_t ref_idx[2]; // 参考帧索引
} PredictionUnit;

// HEVC变换单元(TU)
typedef struct {
uint8_t tu_size; // TU大小
uint8_t cbf_luma; // 亮度CBF
uint8_t cbf_chroma_u; // U色度CBF
uint8_t cbf_chroma_v; // V色度CBF
int16_t *coeffs_luma; // 亮度系数
int16_t *coeffs_chroma_u; // U色度系数
int16_t *coeffs_chroma_v; // V色度系数
} TransformUnit;

// 解析HEVC NAL单元头
int parse_hevc_nal_header(uint16_t header_data, HEVCNALUnitHeader *header) {
header->forbidden_zero_bit = (header_data >> 15) & 0x1;
header->nal_unit_type = (header_data >> 9) & 0x3F;
header->nuh_layer_id = (header_data >> 3) & 0x3F;
header->nuh_temporal_id = (header_data & 0x7) - 1;

if (header->forbidden_zero_bit != 0) {
return -1;
}

return 0;
}

3.3 VP9编码

VP9是Google开发的开源视频编码格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// VP9帧头
typedef struct {
uint8_t frame_marker; // 帧标记
uint8_t profile; // 配置文件
uint8_t show_existing_frame; // 显示现有帧
uint8_t frame_type; // 帧类型
uint8_t show_frame; // 显示帧
uint8_t error_resilient_mode; // 错误恢复模式
uint32_t frame_width; // 帧宽度
uint32_t frame_height; // 帧高度
uint8_t render_width_minus_1; // 渲染宽度-1
uint8_t render_height_minus_1; // 渲染高度-1
uint8_t refresh_frame_flags; // 刷新帧标志
uint8_t ref_frame_idx[3]; // 参考帧索引
uint8_t ref_frame_sign_bias[4]; // 参考帧符号偏置
uint8_t allow_high_precision_mv; // 允许高精度运动向量
uint8_t interpolation_filter; // 插值滤波器
} VP9FrameHeader;

// VP9超级块
typedef struct {
uint8_t sb_size; // 超级块大小 (64x64 or 128x128)
uint8_t partition_type; // 分割类型
uint8_t skip_flag; // 跳过标志
uint8_t segment_id; // 段ID
CodingUnit *coding_units; // 编码单元数组
int num_cus; // 编码单元数量
} VP9SuperBlock;

// VP9分割类型
typedef enum {
PARTITION_NONE = 0, // 无分割
PARTITION_HORZ = 1, // 水平分割
PARTITION_VERT = 2, // 垂直分割
PARTITION_SPLIT = 3 // 四分割
} VP9PartitionType;

4. 容器格式详解

4.1 MP4/MOV格式

MP4基于ISO基础媒体文件格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// MP4原子(Box)头
typedef struct {
uint32_t size; // 原子大小
char type[4]; // 原子类型
uint64_t extended_size; // 扩展大小(当size=1时)
} MP4BoxHeader;

// 文件类型原子(ftyp)
typedef struct {
char major_brand[4]; // 主要品牌
uint32_t minor_version; // 次要版本
char *compatible_brands; // 兼容品牌列表
int num_brands; // 品牌数量
} MP4FileTypeBox;

// 媒体数据原子(mdat)
typedef struct {
uint64_t data_offset; // 数据偏移
uint64_t data_size; // 数据大小
} MP4MediaDataBox;

// 电影原子(moov)
typedef struct {
uint32_t creation_time; // 创建时间
uint32_t modification_time; // 修改时间
uint32_t timescale; // 时间刻度
uint32_t duration; // 持续时间
uint32_t rate; // 播放速率
uint16_t volume; // 音量
uint32_t next_track_id; // 下一个轨道ID
} MP4MovieBox;

// 轨道原子(trak)
typedef struct {
uint32_t track_id; // 轨道ID
uint32_t creation_time; // 创建时间
uint32_t modification_time; // 修改时间
uint32_t duration; // 持续时间
uint16_t layer; // 层
uint16_t alternate_group; // 备用组
uint16_t volume; // 音量
uint32_t width; // 宽度
uint32_t height; // 高度
} MP4TrackBox;

// 解析MP4原子头
int parse_mp4_box_header(FILE *file, MP4BoxHeader *header) {
if (fread(&header->size, 4, 1, file) != 1) return -1;
if (fread(header->type, 1, 4, file) != 4) return -1;

header->size = ntohl(header->size);
header->extended_size = 0;

if (header->size == 1) {
// 64位大小
if (fread(&header->extended_size, 8, 1, file) != 1) return -1;
header->extended_size = ntohll(header->extended_size);
}

return 0;
}

// MP4解复用器
typedef struct {
FILE *file;
MP4FileTypeBox ftyp;
MP4MovieBox moov;
MP4TrackBox *tracks;
int num_tracks;
uint64_t mdat_offset;
uint64_t mdat_size;
} MP4Demuxer;

// 创建MP4解复用器
MP4Demuxer* create_mp4_demuxer(const char *filename) {
MP4Demuxer *demuxer = (MP4Demuxer*)malloc(sizeof(MP4Demuxer));
if (!demuxer) return NULL;

demuxer->file = fopen(filename, "rb");
if (!demuxer->file) {
free(demuxer);
return NULL;
}

demuxer->tracks = NULL;
demuxer->num_tracks = 0;
demuxer->mdat_offset = 0;
demuxer->mdat_size = 0;

// 解析文件结构
if (parse_mp4_structure(demuxer) != 0) {
fclose(demuxer->file);
free(demuxer);
return NULL;
}

return demuxer;
}

// 解析MP4文件结构
int parse_mp4_structure(MP4Demuxer *demuxer) {
MP4BoxHeader header;

while (parse_mp4_box_header(demuxer->file, &header) == 0) {
if (memcmp(header.type, "ftyp", 4) == 0) {
// 解析文件类型
parse_ftyp_box(demuxer->file, &demuxer->ftyp, header.size - 8);
} else if (memcmp(header.type, "moov", 4) == 0) {
// 解析电影信息
parse_moov_box(demuxer->file, &demuxer->moov, header.size - 8);
} else if (memcmp(header.type, "mdat", 4) == 0) {
// 记录媒体数据位置
demuxer->mdat_offset = ftell(demuxer->file);
demuxer->mdat_size = header.size - 8;
fseek(demuxer->file, header.size - 8, SEEK_CUR);
} else {
// 跳过未知原子
fseek(demuxer->file, header.size - 8, SEEK_CUR);
}
}

return 0;
}

4.2 MKV格式

Matroska是一个开放的容器格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// EBML元素头
typedef struct {
uint32_t element_id; // 元素ID
uint64_t element_size; // 元素大小
uint8_t id_length; // ID长度
uint8_t size_length; // 大小长度
} EBMLElementHeader;

// Matroska段信息
typedef struct {
char *title; // 标题
char *muxing_app; // 复用应用
char *writing_app; // 写入应用
uint64_t timecode_scale; // 时间码刻度
double duration; // 持续时间
char *date_utc; // UTC日期
} MatroskaSegmentInfo;

// Matroska轨道
typedef struct {
uint64_t track_number; // 轨道号
uint64_t track_uid; // 轨道UID
uint8_t track_type; // 轨道类型
uint8_t flag_enabled; // 启用标志
uint8_t flag_default; // 默认标志
uint8_t flag_forced; // 强制标志
char *codec_id; // 编解码器ID
uint8_t *codec_private; // 编解码器私有数据
int codec_private_size; // 私有数据大小
char *language; // 语言
char *name; // 名称
} MatroskaTrack;

// 解析EBML变长整数
uint64_t parse_ebml_varint(FILE *file, int *length) {
uint8_t first_byte;
if (fread(&first_byte, 1, 1, file) != 1) return 0;

// 计算长度
int len = 1;
uint8_t mask = 0x80;
while (!(first_byte & mask) && len <= 8) {
mask >>= 1;
len++;
}

if (len > 8) return 0; // 无效长度

uint64_t value = first_byte & (mask - 1);

// 读取剩余字节
for (int i = 1; i < len; i++) {
uint8_t byte;
if (fread(&byte, 1, 1, file) != 1) return 0;
value = (value << 8) | byte;
}

if (length) *length = len;
return value;
}

// 解析EBML元素头
int parse_ebml_element_header(FILE *file, EBMLElementHeader *header) {
int id_length, size_length;

header->element_id = parse_ebml_varint(file, &id_length);
header->element_size = parse_ebml_varint(file, &size_length);

header->id_length = id_length;
header->size_length = size_length;

return (header->element_id != 0 && header->element_size != 0) ? 0 : -1;
}

5. 编解码性能优化

5.1 SIMD优化

使用SIMD指令集加速编解码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <immintrin.h>  // AVX/SSE

// SSE优化的YUV到RGB转换
void yuv_to_rgb_sse(uint8_t *y_plane, uint8_t *u_plane, uint8_t *v_plane,
uint8_t *rgb_output, int width, int height) {
const __m128i y_offset = _mm_set1_epi16(16);
const __m128i uv_offset = _mm_set1_epi16(128);

// YUV到RGB转换系数(定点数)
const __m128i coeff_ry = _mm_set1_epi16(1164); // 1.164 * 1024
const __m128i coeff_ru = _mm_set1_epi16(0);
const __m128i coeff_rv = _mm_set1_epi16(1596); // 1.596 * 1024

const __m128i coeff_gy = _mm_set1_epi16(1164);
const __m128i coeff_gu = _mm_set1_epi16(-391); // -0.391 * 1024
const __m128i coeff_gv = _mm_set1_epi16(-813); // -0.813 * 1024

const __m128i coeff_by = _mm_set1_epi16(1164);
const __m128i coeff_bu = _mm_set1_epi16(2018); // 2.018 * 1024
const __m128i coeff_bv = _mm_set1_epi16(0);

for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x += 8) {
// 加载Y分量(8个像素)
__m128i y_values = _mm_loadl_epi64((__m128i*)(y_plane + y * width + x));
y_values = _mm_unpacklo_epi8(y_values, _mm_setzero_si128());
y_values = _mm_sub_epi16(y_values, y_offset);

// 加载U和V分量(4个像素,需要上采样)
__m128i u_values = _mm_loadl_epi64((__m128i*)(u_plane + (y/2) * (width/2) + x/2));
__m128i v_values = _mm_loadl_epi64((__m128i*)(v_plane + (y/2) * (width/2) + x/2));

u_values = _mm_unpacklo_epi8(u_values, _mm_setzero_si128());
v_values = _mm_unpacklo_epi8(v_values, _mm_setzero_si128());

// 上采样U和V(每个值重复两次)
u_values = _mm_unpacklo_epi16(u_values, u_values);
v_values = _mm_unpacklo_epi16(v_values, v_values);

u_values = _mm_sub_epi16(u_values, uv_offset);
v_values = _mm_sub_epi16(v_values, uv_offset);

// 计算RGB分量
__m128i r_values = _mm_add_epi16(
_mm_mulhi_epi16(y_values, coeff_ry),
_mm_mulhi_epi16(v_values, coeff_rv)
);

__m128i g_values = _mm_add_epi16(
_mm_add_epi16(
_mm_mulhi_epi16(y_values, coeff_gy),
_mm_mulhi_epi16(u_values, coeff_gu)
),
_mm_mulhi_epi16(v_values, coeff_gv)
);

__m128i b_values = _mm_add_epi16(
_mm_mulhi_epi16(y_values, coeff_by),
_mm_mulhi_epi16(u_values, coeff_bu)
);

// 限制范围并打包
r_values = _mm_packus_epi16(r_values, _mm_setzero_si128());
g_values = _mm_packus_epi16(g_values, _mm_setzero_si128());
b_values = _mm_packus_epi16(b_values, _mm_setzero_si128());

// 交错存储RGB
for (int i = 0; i < 8 && x + i < width; i++) {
rgb_output[(y * width + x + i) * 3 + 0] = _mm_extract_epi8(r_values, i);
rgb_output[(y * width + x + i) * 3 + 1] = _mm_extract_epi8(g_values, i);
rgb_output[(y * width + x + i) * 3 + 2] = _mm_extract_epi8(b_values, i);
}
}
}
}

// AVX2优化的DCT变换
void dct_8x8_avx2(int16_t *input, int16_t *output) {
// DCT系数矩阵(简化)
const __m256i dct_coeff[8] = {
_mm256_set_epi16(181, 181, 181, 181, 181, 181, 181, 181,
181, 181, 181, 181, 181, 181, 181, 181),
// ... 其他系数
};

// 执行8x8 DCT变换
for (int i = 0; i < 8; i++) {
__m256i row = _mm256_loadu_si256((__m256i*)(input + i * 8));

// 矩阵乘法(简化)
__m256i result = _mm256_setzero_si256();
for (int j = 0; j < 8; j++) {
__m256i coeff = dct_coeff[j];
__m256i prod = _mm256_mullo_epi16(row, coeff);
result = _mm256_add_epi16(result, prod);
}

_mm256_storeu_si256((__m256i*)(output + i * 8), result);
}
}

5.2 多线程编解码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include <pthread.h>

// 编码任务结构
typedef struct {
uint8_t *input_frame; // 输入帧
uint8_t *output_buffer; // 输出缓冲区
int frame_width; // 帧宽度
int frame_height; // 帧高度
int start_row; // 起始行
int end_row; // 结束行
int thread_id; // 线程ID
pthread_mutex_t *mutex; // 互斥锁
pthread_cond_t *condition; // 条件变量
int *completed_threads; // 完成的线程数
int total_threads; // 总线程数
} EncodingTask;

// 编码线程函数
void* encoding_thread(void *arg) {
EncodingTask *task = (EncodingTask*)arg;

// 处理分配的行
for (int y = task->start_row; y < task->end_row; y++) {
for (int x = 0; x < task->frame_width; x += 16) {
// 处理16x16宏块
encode_macroblock(task->input_frame, task->output_buffer,
x, y, task->frame_width, task->frame_height);
}
}

// 通知完成
pthread_mutex_lock(task->mutex);
(*task->completed_threads)++;
if (*task->completed_threads == task->total_threads) {
pthread_cond_broadcast(task->condition);
}
pthread_mutex_unlock(task->mutex);

return NULL;
}

// 多线程编码器
typedef struct {
pthread_t *threads; // 线程数组
EncodingTask *tasks; // 任务数组
int num_threads; // 线程数
pthread_mutex_t mutex; // 互斥锁
pthread_cond_t condition; // 条件变量
int completed_threads; // 完成的线程数
} MultiThreadEncoder;

// 创建多线程编码器
MultiThreadEncoder* create_mt_encoder(int num_threads) {
MultiThreadEncoder *encoder = (MultiThreadEncoder*)malloc(sizeof(MultiThreadEncoder));
if (!encoder) return NULL;

encoder->num_threads = num_threads;
encoder->threads = (pthread_t*)malloc(num_threads * sizeof(pthread_t));
encoder->tasks = (EncodingTask*)malloc(num_threads * sizeof(EncodingTask));
encoder->completed_threads = 0;

if (!encoder->threads || !encoder->tasks) {
free(encoder->threads);
free(encoder->tasks);
free(encoder);
return NULL;
}

pthread_mutex_init(&encoder->mutex, NULL);
pthread_cond_init(&encoder->condition, NULL);

return encoder;
}

// 编码帧
int encode_frame_mt(MultiThreadEncoder *encoder, uint8_t *input_frame,
uint8_t *output_buffer, int width, int height) {
encoder->completed_threads = 0;

int rows_per_thread = height / encoder->num_threads;

// 创建任务
for (int i = 0; i < encoder->num_threads; i++) {
EncodingTask *task = &encoder->tasks[i];

task->input_frame = input_frame;
task->output_buffer = output_buffer;
task->frame_width = width;
task->frame_height = height;
task->start_row = i * rows_per_thread;
task->end_row = (i == encoder->num_threads - 1) ? height : (i + 1) * rows_per_thread;
task->thread_id = i;
task->mutex = &encoder->mutex;
task->condition = &encoder->condition;
task->completed_threads = &encoder->completed_threads;
task->total_threads = encoder->num_threads;

// 创建线程
if (pthread_create(&encoder->threads[i], NULL, encoding_thread, task) != 0) {
return -1;
}
}

// 等待所有线程完成
pthread_mutex_lock(&encoder->mutex);
while (encoder->completed_threads < encoder->num_threads) {
pthread_cond_wait(&encoder->condition, &encoder->mutex);
}
pthread_mutex_unlock(&encoder->mutex);

// 等待线程结束
for (int i = 0; i < encoder->num_threads; i++) {
pthread_join(encoder->threads[i], NULL);
}

return 0;
}

6. 实际应用示例

6.1 简单的视频播放器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import cv2
import numpy as np
from threading import Thread, Lock
import time

class SimpleVideoPlayer:
def __init__(self):
self.cap = None
self.is_playing = False
self.current_frame = None
self.frame_lock = Lock()
self.fps = 30
self.frame_count = 0
self.total_frames = 0

def load_video(self, filename):
"""加载视频文件"""
self.cap = cv2.VideoCapture(filename)
if not self.cap.isOpened():
return False

self.fps = self.cap.get(cv2.CAP_PROP_FPS)
self.total_frames = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT))
return True

def play(self):
"""播放视频"""
if not self.cap:
return

self.is_playing = True
play_thread = Thread(target=self._play_loop)
play_thread.start()

def _play_loop(self):
"""播放循环"""
frame_time = 1.0 / self.fps

while self.is_playing and self.cap.isOpened():
start_time = time.time()

ret, frame = self.cap.read()
if not ret:
break

with self.frame_lock:
self.current_frame = frame
self.frame_count += 1

# 控制帧率
elapsed = time.time() - start_time
sleep_time = frame_time - elapsed
if sleep_time > 0:
time.sleep(sleep_time)

def get_current_frame(self):
"""获取当前帧"""
with self.frame_lock:
return self.current_frame.copy() if self.current_frame is not None else None

def stop(self):
"""停止播放"""
self.is_playing = False
if self.cap:
self.cap.release()

# 使用示例
if __name__ == "__main__":
player = SimpleVideoPlayer()

if player.load_video("test_video.mp4"):
player.play()

# 显示视频
while True:
frame = player.get_current_frame()
if frame is not None:
cv2.imshow('Video Player', frame)

if cv2.waitKey(1) & 0xFF == ord('q'):
break

player.stop()
cv2.destroyAllWindows()

6.2 音频格式转换器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import wave
import struct
import numpy as np
from scipy.io import wavfile

class AudioConverter:
def __init__(self):
self.supported_formats = ['wav', 'raw', 'pcm']

def convert_sample_rate(self, audio_data, original_rate, target_rate):
"""采样率转换(简单线性插值)"""
if original_rate == target_rate:
return audio_data

# 计算重采样比例
ratio = target_rate / original_rate
new_length = int(len(audio_data) * ratio)

# 线性插值
old_indices = np.linspace(0, len(audio_data) - 1, new_length)
new_audio = np.interp(old_indices, np.arange(len(audio_data)), audio_data)

return new_audio.astype(audio_data.dtype)

def convert_bit_depth(self, audio_data, target_depth):
"""位深度转换"""
if target_depth == 16:
if audio_data.dtype == np.float32:
return (audio_data * 32767).astype(np.int16)
elif audio_data.dtype == np.int32:
return (audio_data >> 16).astype(np.int16)
elif target_depth == 32:
if audio_data.dtype == np.int16:
return audio_data.astype(np.int32) << 16
elif audio_data.dtype == np.float32:
return (audio_data * 2147483647).astype(np.int32)

return audio_data

def stereo_to_mono(self, stereo_data):
"""立体声转单声道"""
if len(stereo_data.shape) == 1:
return stereo_data
return np.mean(stereo_data, axis=1)

def mono_to_stereo(self, mono_data):
"""单声道转立体声"""
if len(mono_data.shape) == 2:
return mono_data
return np.column_stack((mono_data, mono_data))

def convert_format(self, input_file, output_file,
target_rate=None, target_depth=None, target_channels=None):
"""格式转换主函数"""
# 读取输入文件
try:
sample_rate, audio_data = wavfile.read(input_file)
except:
return False

# 采样率转换
if target_rate and target_rate != sample_rate:
audio_data = self.convert_sample_rate(audio_data, sample_rate, target_rate)
sample_rate = target_rate

# 声道转换
if target_channels:
if target_channels == 1 and len(audio_data.shape) == 2:
audio_data = self.stereo_to_mono(audio_data)
elif target_channels == 2 and len(audio_data.shape) == 1:
audio_data = self.mono_to_stereo(audio_data)

# 位深度转换
if target_depth:
audio_data = self.convert_bit_depth(audio_data, target_depth)

# 写入输出文件
try:
wavfile.write(output_file, sample_rate, audio_data)
return True
except:
return False

# 使用示例
converter = AudioConverter()
converter.convert_format('input.wav', 'output.wav',
target_rate=22050, target_depth=16, target_channels=1)

7. 格式选择指南

7.1 音频格式选择

应用场景 推荐格式 原因
高质量音乐 FLAC, WAV 无损压缩,保持原始质量
流媒体 AAC, MP3 压缩率高,兼容性好
语音通话 Opus, AMR 低延迟,适合实时传输
游戏音效 OGG, WAV 循环播放友好,低CPU占用
广播 MP3, AAC 标准化程度高,设备支持广泛

7.2 视频格式选择

应用场景 推荐格式 编码器 容器
在线视频 H.264/H.265 x264/x265 MP4
直播流 H.264 x264 FLV/HLS
高质量存档 H.265/AV1 x265/libaom MKV
实时通信 VP8/VP9 libvpx WebM
移动设备 H.264 硬件编码器 MP4

总结

本文深入探讨了音视频格式与编解码技术的核心内容:

音频技术要点:

  • PCM作为基础格式,理解数字音频的本质
  • MP3的感知编码原理和MDCT变换
  • AAC的先进特性和更高压缩效率
  • FLAC的无损压缩算法和应用场景

视频技术要点:

  • H.264/AVC的宏块预测和变换编码
  • H.265/HEVC的编码单元结构和效率提升
  • VP9的开源特性和技术创新
  • 运动估计和帧间预测的核心算法

容器格式特性:

  • MP4的原子结构和广泛兼容性
  • MKV的开放性和丰富功能
  • 不同容器的适用场景和技术特点

性能优化策略:

  • SIMD指令集的并行计算优势
  • 多线程编解码的架构设计
  • 硬件加速的应用和限制

实际应用考虑:

  • 根据应用场景选择合适的格式
  • 平衡质量、文件大小和兼容性
  • 考虑编解码性能和资源消耗

掌握这些音视频格式和编解码技术,为开发高质量的多媒体应用提供了坚实的技术基础。在实际项目中,需要根据具体需求权衡各种因素,选择最适合的技术方案。

版权所有,如有侵权请联系我