H264初探

文章详细解释了H.264编码中的NAL单元(NALU)结构,包括其作用、类型和封装,以及SPS(序列参数集)和PPS(图片参数集)在视频编码中的重要性。讲解了如何通过SPS和PPS传递视频参数和保证解码一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、NAL(Network Abstraction Layer)

在 H.264 编码中,NAL(Network Abstraction Layer)是一个关键的概念,它负责将编码的视频数据封装成适合各种网络传输和存储的形式。

NAL 单元(NAL Units,简称 NALUs)是 H.264 编码视频流中的基本数据包,每个 NALU 包含一个原始字节序列负载(Raw Byte Sequence Payload,RBSP),它是编码视频数据的实际内容。

NALU 的结构如下:

  • 起始码(Start Code):通常是一个字节的 0x00,后面跟着两个字节的 0x00 0x01或者三个字节的0x00 0x00 0x01,用于标识 NALU 的开始。在流模式下,起始码可以帮助解码器定位和同步到 NALU 的开始位置。
  • NAL 头(NAL Header):紧随起始码之后的一个字节,包含 NALU 的类型和一些其他信息。NAL 头的结构通常如下:

F (bit 0): 禁止位(Forbidden zero bit),在标准的编码中,这个位应该设置为0。如果设置为1,表示NAL单元的数据可能存在错误。

NRI (bits 1-2): NAL引用指示(NAL reference indicator),这两位用来指示NAL单元的重要性。值越大,表示NAL单元越重要。例如,对于解码其他NAL单元不是必需的单元(如SEI或非参考帧),这个值可能是0。对于关键帧(I帧)的NAL单元,这个值通常较高。

Type (bits 3-7): NAL单元类型(NAL unit type),这5位用来指示NAL单元的类型。不同的值对应不同类型的NAL单元,例如:

1: 非IDR(即非关键帧)图像中的编码片段
5: IDR图像的编码片段(关键帧)
6: 补充增强信息单元(SEI)
7: 序列参数集(SPS)
8: 图像参数集(PPS)
9: 分隔符

NALU 类型主要分为两大类:VCL(Video Coding Layer)和非 VCL。VCL NALU 包含实际的视频数据,而非 VCL NALU 包含编码视频流的辅助信息,如 SPS 和 PPS。

VCL NALU:包含编码的视频帧数据,如 I 帧、P 帧和 B 帧。
非 VCL NALU:包含序列参数集(SPS)、图像参数集(PPS)、访问单元分隔符(AUD)等元数据,这些信息对于初始化解码器和正确解码视频流至关重要。

在传输和存储时,NALU 可以通过不同的方式封装,例如在 RTP(Real-time Transport Protocol)中用于实时视频传输,或者在 MP4 文件中用于存储和播放。封装方式会根据应用场景的需求来选择,以确保视频数据的有效传输和解码。

总结来说,NAL 是 H.264 编码中的一个重要组成部分,它通过封装编码的视频数据,使得视频流能够适应不同的网络和存储环境,同时为解码器提供必要的信息以正确解码视频内容。

二、SPS(Sequence Parameter Set)和PPS(Picture Parameter Set)

什么是sps和pps?

SPS包含了一系列影响整个视频序列的参数,这些参数对于解码器来说是必须知道的,以便能够正确解码视频流中的图像。SPS的一些典型参数包括:

视频编码级别和配置文件
视频分辨率
帧率
色彩空间
时间尺度和时间戳
编码使用的工具和特性(比如B帧、CABAC等)

SPS本身并不直接包含帧率(frame rate)信息。帧率通常是通过两个参数间接反映的:

time_scale:这个参数表示在一秒钟内有多少个时间单位。
num_units_in_tick:这个参数表示一个帧或一个场(field)占用的时间单位数。

帧率可以通过这两个参数计算得出,计算公式如下:

Frame rate = time_scale / (2 * num_units_in_tick)

这个公式中的“2”是因为在交错视频(interlaced video)中,一个时间单位可能只代表半帧(一个场)。对于逐行扫描视频(progressive video),这个“2”可能不需要。

需要注意的是,这种计算得到的帧率是序列的最大帧率,实际的帧率可能会因为编码时使用了不同的帧间隔(frame interval)而有所不同。此外,有些视频可能会使用固定的帧率,而有些视频则可能使用可变帧率(VFR),在这种情况下,每个帧的显示时间可能会有所不同。

在实际应用中,如果你需要获取视频的帧率,通常可以通过解析视频文件的元数据或使用视频分析工具来获取,而不是直接从SPS参数中读取。

在SPS中,视频分辨率通常通过以下参数来表示:

pic_width_in_mbs_minus1 和 pic_height_in_map_units_minus1:这两个参数分别表示宽度和高度的宏块(macroblock)数量减去1。在H.264中,一个宏块的大小是16x16像素。因此,实际的视频宽度和高度可以通过这两个参数计算得出。

frame_crop_left_offset, frame_crop_right_offset, frame_crop_top_offset, frame_crop_bottom_offset:这些参数表示视频帧的裁剪信息。如果视频帧被裁剪,这些参数将提供裁剪的宏块数量,从而可以计算出裁剪后的实际视频分辨率。

例如,如果你有一个H.264视频流,SPS中的pic_width_in_mbs_minus1为79和pic_height_in_map_units_minus1为44,那么视频的宽度和高度可以这样计算:

宽度 = (79 + 1) * 16 = 1280像素 高度 = (44 + 1) * 16 = 720像素

因此,视频的分辨率是1280x720。

在解析SPS时,解码器会读取这些参数来设置解码过程中使用的分辨率。如果你想手动解析SPS来获取视频分辨率,你可能需要使用视频编码分析工具或编写代码来解析SPS的比特流数据。

PPS包含了一些影响单个图像或一组图像(GOP,Group of Pictures)的参数。这些参数通常与图像的编码过程更为直接相关。PPS的一些典型参数包括:

量化参数
去块滤波设置
切片分组信息
参考帧列表

在视频流中,SPS和PPS通常在流的开始处发送,并且可能会周期性地重复发送,以确保解码器可以同步并正确解码视频帧。这些参数集在视频会话开始时或者视频参数发生变化时必须被发送到解码器,因为没有它们,解码器将无法理解后续的视频数据。

在实际应用中,比如在网络视频流或文件中,SPS和PPS通常被嵌入到视频流的特定位置,如IDR帧(立即刷新帧)之前,以便解码器可以在必要时访问这些参数。在视频文件格式(如MP4)中,SPS和PPS可能被存储在文件的元数据区域,以便在开始播放之前就可以读取它们。

sps和pps在视频流中是变化的吗?

在一个视频编码的会话中,SPS和PPS通常在开始时发送,并且在视频序列不变的情况下它们是不变的。然而,如果视频参数发生变化(比如分辨率或帧率改变),则需要生成新的SPS和PPS来描述新的视频序列参数。

在视频流中,SPS和PPS可能会周期性地重复发送,以确保如果有新的解码器加入或者由于网络问题导致数据丢失,解码器仍然可以同步并正确解码后续的视频帧。

总结来说,SPS和PPS在视频参数不变的情况下是不变的,但如果视频参数发生变化,它们需要更新以反映新的参数设置。

ref:

【科普】“视频”是怎么来的?H.264、码率这些词又是什么意思?_哔哩哔哩_bilibili

H.264编解码原理浅析 - 知乎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值