问题描述
向srs媒体服务上推送rtmp流,推送失败
分析过程
srs日志分析
从日志中看到发生错误时层次调用关系
[2023-09-05 11:10:29.933][Error][13594][9w5og10q][11] serve error code=3001 : service cycle : rtmp: stream service : rtmp: receive thread : handle publish message : rtmp: consume message : rtmp: consume video : meta update video : demux SPS/PPS : avc decode sequence header
去代码中搜索"avc decode sequence header"相关信息,发现是解析sps/pps信息异常
// src/kernel/srs_kernel_codec.cpp
srs_error_t SrsFormat::avc_demux_sps_pps(SrsBuffer* stream)
{
// AVCDecoderConfigurationRecord
// 5.2.4.1.1 Syntax, ISO_IEC_14496-15-AVC-format-2012.pdf, page 16
int avc_extra_size = stream->size() - stream->pos();
if (avc_extra_size > 0) {
char *copy_stream_from = stream->data() + stream->pos();
vcodec->avc_extra_data = std::vector<char>(copy_stream_from, copy_stream_from + avc_extra_size);
}
if (!stream->require(6)) {
return srs_error_new(ERROR_HLS_DECODE_ERROR, "avc decode sequence header");
}
......
}
stream对应的buffer中不够6个字节???
抓包分析
推流端给服务端发送完publish之后,服务端回复的onStatus,以及客户端给服务端发送的setDataFrame、onMetaData都没有被解析成rtmp,只能根据rtmp协议标准分析onMetaData(及ECMA Array)之后的数据,srs日志中也表示获取到了meta data
[2023-09-05 11:10:29.927][Trace][13594][9w5og10q] got metadata, width=1280, height=720, vcodec=7, acodec=10
再结合srs的日志,猜测是sps/pps解析引起的
onMetaData的"End Of Object Marker"对应着0x00 0x00 0x09序列,其后对应着其他的rtmp包
rtmp的header中各字段含义表示为
字段分类 | 字段含义 | 位宽 | 描述 | |
Header | format | 2bits | 0表示header长度为11字节 1表示header长度为7字节 2表示header长度为3字节 3表示header长度为0字节 (不含本字节) | |
ChunkStreamID | 6bits | |||
TimeStamp | 3Bytes | |||
BodySize | 3Bytes | |||
TypeId | 1Byte | 0x08对应语音数据 0x09对应视频数据 | ||
StreamId | 4Bytes | |||
Body (需要根据header中TypeId区分,这里只描述audio/video) | Control | 1Byte | 视频数据 | Type: 4bits, 1表示Key Frame; 2表示inter-frame |
Format: 4bits, 7表示H264 | ||||
语音数据 | Format: 4bits, 10表示HE-AAc SampleRate: 2bits, 3表示44kHz SampleSize: 1bit, 1表示16bits Channels: 1bit, 1表示Stereo | |||
Data | BodySize - 1 |
抓包和rtmp协议规范对着看吧,第一个视频帧长度为5并且有效数据是00 00 00 00,代码中要求长度是6,所以对上号了
结论
推流端首帧视频数据长度为5,真实数据为00 00 00 00, 代码中要求是6,所以srs代码中校验不通过,报错。
猜测是客户端首帧编码异常,或者发送的太早了,数据还没编码好就开始发送了......
参考
setDataFrame、onMetaData协议格式参考手撕Rtmp协议细节(8)——publish推流_视界音你而不同的博客-CSDN博客