SPS、PPS

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPS、PPS相关的知识,希望对你有一定的参考价值。

参考技术A 在 H.264 流中,有两种 NALU 极其重要

一般情况 SPS 和 PPS 的 NAL Unit 通常位于整个码流的起始位置。
封装文件一般进保存一次,位于文件头部, SPS/PPS 在整个解码过程中复用,不发生变化。
然而对于实时流,通常是从流中间开始解码,因此需要在每个 I帧 前添加 SPS 和 PPS ;
如果编码器在编码过程中改变了码流参数(如分辨率),需要重新调整 SPS 和 PPS 数据。

NAL ( Network Abstract Layer ),即网络抽象层
在 H.264/AVC 视频编码标准中,整个系统框架被分为了两个层面:

视频编码层往往与网络抽象层(NAL)相互配合,标准的 NAL-unit 总共规范( Profile )有12种,这12种型式可粗分成 VCL NAL-unit 及 non-VCL NAL-unit ,其中 VCL NAL-unit 是指 NAL-unit 中存放的完全是VCL的影像资料。

现实中的传输系统是多样化的,其可靠性,服务质量,封装方式等特征各不相同,NAL这一概念的提出提供了一个视频编码器和传输系统的友好接口,使得编码后的视频数据能够有效的在各种不同的网络环境中传输。

使用ffmpeg命令推送rtsp流,不包含SPS和PPS帧

【中文标题】使用ffmpeg命令推送rtsp流,不包含SPS和PPS帧【英文标题】:use ffmpeg command to push rtsp stream, it doesn't contain SPS and PPS frame 【发布时间】:2022-01-07 03:17:16 【问题描述】:

我使用 python 和 opencv-python 从视频中捕获帧,然后使用 ffmpeg 命令通过管道推送 rtsp 流。我可以通过 gstreamer 和 vlc 播放 rtsp 流。但是,显示设备无法解码和播放 rtsp-stream,因为它无法接收 SPS 和 PPS 帧。使用wireshark抓流,发现不发送sps和pps帧,只发送IDR 帧。

关键代码如下。

# ffmpeg command
command = ['ffmpeg',
           '-re',
           '-y',
           '-f', 'rawvideo',
           '-vcodec', 'rawvideo',
           '-pix_fmt', 'bgr24',
           '-s', "x".format(width, height),
           '-r', str(fps),
           '-i', '-',
           '-c:v', 'libx264',
           '-preset', 'ultrafast',
           '-f', 'rtsp',
           '-flags', 'local_headers', 
           '-rtsp_transport', 'tcp',
           '-muxdelay', '0.1', 
           rtsp_url]
 
p = sp.Popen(command, stdin=sp.PIPE)
 
 
while (cap.isOpened()):
    ret, frame = cap.read()
    if not ret:
        cap = cv2.VideoCapture(video_path)
        continue
    p.stdin.write(frame.tobytes()

我可能错过了 ffmpeg 命令的一些选项吗?

【问题讨论】:

【参考方案1】:

尝试添加参数'-bsf:v', 'dump_extra'

根据FFmpeg Bitstream Filters Documentation:

dump_extra 将额外数据添加到过滤数据包的开头,除非所述数据包已经完全以要添加的额外数据开头。

过滤器应该为每个关键帧添加 SPS 和 PPS NAL 单元。


这是一个完整的代码示例:

import subprocess as sp
import cv2

rtsp_url = 'rtsp://localhost:31415/live.stream'

video_path = 'input.mp4'


# We have to start the server up first, before the sending client (when using TCP). See: https://trac.ffmpeg.org/wiki/StreamingGuide#Pointtopointstreaming
ffplay_process = sp.Popen(['ffplay', '-rtsp_flags', 'listen', rtsp_url])  # Use FFplay sub-process for receiving the RTSP video.


cap = cv2.VideoCapture(video_path)

width  = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))  # Get video frames width
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))  # Get video frames height
fps = int(cap.get(cv2.CAP_PROP_FPS))  # Get video framerate

    
# FFmpeg command
command = ['ffmpeg',
           '-re',
           '-y',
           '-f', 'rawvideo',
           '-vcodec', 'rawvideo',
           '-pix_fmt', 'bgr24',
           '-s', "x".format(width, height),
           '-r', str(fps),
           '-i', '-',
           '-c:v', 'libx264',
           '-preset', 'ultrafast',
           '-f', 'rtsp',
           #'-flags', 'local_headers', 
           '-rtsp_transport', 'tcp',
           '-muxdelay', '0.1',
           '-bsf:v', 'dump_extra',
           rtsp_url]

p = sp.Popen(command, stdin=sp.PIPE)

while (cap.isOpened()):
    ret, frame = cap.read()

    if not ret:
        break

    p.stdin.write(frame.tobytes())


p.stdin.close()  # Close stdin pipe
p.wait()  # Wait for FFmpeg sub-process to finish
ffplay_process.kill()  # Forcefully close FFplay sub-process

注意事项:

'-flags', 'local_headers' 在我的 FFmpeg 版本中不是有效参数。 我不知道如何验证我的解决方案,所以我可能是错的......

【讨论】:

非常感谢!问题我已经解决了,我们的解决方法都是一样的!

以上是关于SPS、PPS的主要内容,如果未能解决你的问题,请参考以下文章

ffmpeg 添加 sps pps

H264码流中SPS PPS详解

具有多个 PPS 和 SPS 的 H264

SPS & PPS in H.264 详解

H264参数SPS(序列参数集)和PPS(图像参数集)说明

H264码流中NALU sps pps IDR帧的理解