我在使用ffmpeg库解码IP摄像头流(h.265)时遇到问题。
我使用Live 555接收RTP负载。
mMediaSession->readSource()->getNextFrame(mVideoBuffer.data(),
mVideoBuffer.size(), Stream::Static_PayloadRead, this, Stream::Static_StreamClose, this);
前两个字节(在开始代码0001之后)具有nal_unit_header。我正在从1-6位((NALU[0] >> 1)& 0x 3F)中检索类型。然后我根据NALU类型处理数据:
enum NalUnitType
{
NAL_UNIT_CODED_SLICE_TRAIL_N = 0, // 0
NAL_UNIT_CODED_SLICE_TRAIL_R, // 1
NAL_UNIT_CODED_SLICE_TSA_N, // 2
NAL_UNIT_CODED_SLICE_TLA, // 3
NAL_UNIT_CODED_SLICE_STSA_N, // 4
NAL_UNIT_CODED_SLICE_STSA_R, // 5
NAL_UNIT_CODED_SLICE_RADL_N, // 6
NAL_UNIT_CODED_SLICE_DLP, // 7
NAL_UNIT_CODED_SLICE_RASL_N, // 8
NAL_UNIT_CODED_SLICE_TFD, // 9
NAL_UNIT_RESERVED_10,
...
NAL_UNIT_CODED_SLICE_BLA, // 16
NAL_UNIT_CODED_SLICE_BLANT, // 17
NAL_UNIT_CODED_SLICE_BLA_N_LP, // 18
NAL_UNIT_CODED_SLICE_IDR, // 19 // Current name in the spec: IDR_W_DLP
NAL_UNIT_CODED_SLICE_IDR_N_LP, // 20
NAL_UNIT_CODED_SLICE_CRA, // 21
NAL_UNIT_RESERVED_22,
...
NAL_UNIT_VPS, // 32
NAL_UNIT_SPS, // 33
NAL_UNIT_PPS, // 34
NAL_UNIT_ACCESS_UNIT_DELIMITER, // 35
NAL_UNIT_EOS, // 36
NAL_UNIT_EOB, // 37
NAL_UNIT_FILLER_DATA, // 38
NAL_UNIT_SEI, // 39 Prefix SEI
NAL_UNIT_SEI_SUFFIX, // 40 Suffix SEI
...
NAL_UNIT_INVALID,
};
如果buffer没有开始代码,我会在发送到FFmpeg之前,在有效载荷数据的开始处添加0x 00000001。相机正在发送这些NALU(以相同的顺序):
- HEVC_NAL_VPS,
- HEVC_NAL_SPS,
- HEVC_NAL_PPS,
- HEVC_NAL_IDR_W_RADL,
- HEVC_NAL_IDR_W_RADL,
- HEVC_NAL_IDR_W_RADL,
- HEVC_NAL_TRAIL_R,
- HEVC_NAL_TRAIL_R.
我的解决方案部分工作,因为我有1/3的图像解码。其他2个HEVC_NAL_IDR_W_RADL切片得到FFmpeg错误:“帧中的第一个切片丢失”。如果我降低流分辨率,则我具有1/2图像和一个附加HEVC_NAL_IDR_W_RADL切片。
类似的代码与H.264流一起工作,所以我知道(我希望)Live 555和FFmpeg代码应该没问题。
Live 555不会重新组装I帧(http://lists.live555.com/pipermail/live-devel/2016-September/020244.html)
是否有一种特定的方法来重新组装多个切片中发送的帧。我甚至尝试组装帧,因为它将是分段单元NAL类型49(How to depacketize the fragmented frames in RTP data (over UDP) for H265/HEVC?)
非常感谢
1条答案
按热度按时间b09cbbtk1#
它的确定只是缝合在一起。下面描述的解决方案适用于我与FFmpeg + Live555。
对于I切片,我执行以下操作:
对于非I切片:
要知道切片是否是其帧的第一个切片,您可以检查
NALU[2] & 0x80
,它应该仅在初始切片中为非零。Live555保证给予切片正确的顺序。因此,当你遇到一个开始新帧的切片时,只需将之前拼接的切片馈送到FFmpeg HEVC解码器并开始拼接一个新帧。NALU[1] & 0x80
。