海康PS码流分析

背景:通过使用海康SDK和EHOME_SDK,可以回调得到海康摄像头的原始PS码流。对PS码流进行解析分包,能够得到H264/H265视频流和AAC/G711音频流。然后可以将音视频通过RTMP打包封装之后发送到流媒体平台zlmediakit。因此有必要对海康PS码流格式进行分析。

1.海康PS码流:前面40位是海康私有码流头,可忽略。49 4D 4B 48 *****

 2.PS码流:剩余的就是一段一段的PS包

 

3.PS Header:参考https://blog.csdn.net/weixin_44517656/article/details/108412988

00 00 01 BA 46 FA F7 C4 54 01 00 00 03 FE FF FF 
00 00 00 01   

20byte:
4byte    start: 00 00 01 BA
9byte    buf: 46 FA F7 C4 54 01 00 00 03
1byte    stufflen: FE FE&07 = 6
6byte    stuffer:FF FF 00 00 00 01

4.Program Stream Map 参考:https://www.cnblogs.com/zhumengke/articles/11681668.html

 

00 00 01 BC 00 5A E0 FF 00 24 40 0E 48 4B 00 00
17 9D 3E B4 60 00 00 FF FF FF 41 12 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2C
1B E0 00 10 42 0E 00 00 A0 21 05 00 02 D0 12 1C
3F 00 1C 21 0F C0 00 0C 43 0A 00 00 FE 00 FA 03
01 F4 03 FF BD BD 00 00 BF BF 00 00 00 00 00 00  

4byte    start: 00 00 01 BC
2byte    packlen: 00 5A    = 90
2byte    packinfo: E0 FF
2byte    program_strem_info_len: 00 24 = 36
36byte   descriptor: 40 0E 48 4B 00 00 17 9D 3E B4 60 00 00 FF FF FF 41 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    aa 0x40 表示当前为BASIC信息
    aa+1 0x0E = 14 BASIC信息长度
    aa+2~aa+3 0x48 0x4B 公司描述符
    aa+6~aa+11 0x17 0x9D 0x3E 0xB4 0x60 0x00 0x00 当前年月日时分秒及加密类型
    
    bb 0x41 表示当前为DEVICE信息
    bb+1 0x12 = 18 DEVICE信息的长度
    bb+4~bb+19 设备ID号

2byte    elementary_stream_map_length: 00 2C = 44
1byte    stream_type: 1B    0x1B --> H264    0x24 --> H265
1byte    elementary_stream_id: E0       0xE0 --> 视频   0xC0 --> 音频
2byte    elementary_stream_info_len: 00 10 = 16
16byte   descriptor: 42 0E 00 00 A0 21 05 00 02 D0 12 1C 3F 00 1C 21
    aa 0x42 表示当前为VIDEO信息
    aa+1 0x0E = 14 VIDEO信息长度
    aa+2~aa+3 0x00 0x00 编码器版本
    aa+4~aa+5 0xA0 0x21 编码器年月日
    aa+6~aa+7 0x05 0x00 = 1280 图像宽度
    aa+8~aa+9 0x02 0xD0 = 720 图像高度
    aa+10 0x12 是否隔行扫描,b帧数目,是否为SVC码流,是否使用e帧,最大参考帧数目
    aa+11 0x1C 水印类型,显示时是否需要反隔行
    aa+12 0x3F JPEG的Q值
    aa+13~aa+15 0x00 0x1C 0x21 以1/90000s为单位的两帧间时间间隔,是否使用固定帧率

1byte    stream_type: 0F        0x90 --> g711 0x0F --> aac
1byte    elementary_stream_id: C0       0xE0 --> 视频   0xC0 --> 音频
2byte    elementary_stream_info_len: 00 0C = 12
12byte   descriptor: 43 0A 00 00 FE 00 FA 03 01 F4 03 FF
    dd 0x43 表示当前为AUDIO信息
    dd+1 0x0A AUDIO信息长度
    dd+2~dd+3 0x00 0x00 音频帧长度
    dd+4 0xFE 音频声道数
    dd+5~dd+7 0x00 0xFA 0x03 音频采样率
    dd+8~dd+10 0x01 0xF4 0x03 音频比特率

2byte 私有数据信息 BD BD
4byte CRC校验 00 00 BF BF

5. PES: SPS报文 可参考:https://blog.csdn.net/smartgps2008/article/details/124130429

00 00 01 E0 00 26 8C 80 07 21 BE BD F1 15 FF FC
00 00 00 01 67 4D 00 1F 9D A8 14 01 6E 9B 80 80
80 A0 00 00 03 00 20 00 00 06 50 80

4byte    start: 00 00 01 E0
2byte    packlen: 00 26    = 38
2byte        packinfo: 8C 80
1byte        stufflen: 07
7byte        stuff: 21 BE BD F1 15 FF FC
4byte    start: 00 00 00 01
1byte    nalType: 67 -->SPS包
23byte   sps: 4D 00 1F 9D A8 14 01 6E 9B 80 80 80 A0 00 00 03 00 20 00 00 06 50 80
    ss 0x4D = 77  profile_idc基准档次,66 --> baseline profile, 77 --> main profile,88 --> extended profile
    后面可以解析出width、height、fps等视频信息,参见:https://github.com/cdebug/h264_to_rtmp/blob/master/src/sps_decode.h

6.PES: PPS报文

00 00 01 E0 00 0E 8C 00 03 FF FF FC 00 00 00 01
68 EE 3C 80   

4byte    start: 00 00 01 E0
2byte    packlen:00 0E  = 14
2byte    packinfo: 8C 00
1byte    stufflen: 03
3byte       stuff: FF FF FC
4byte       start: 00 00 00 01 
1byte    nalType: 68 -->PPS包
3byte    pps: 3C 80

7.PES:  I帧报文

00 00 01 E0 13 FA 8C 00 02 FF FD 00 00 00 01 65
B8 00 00 08 73 C0 AF F8 80 D7 3E AB C0 4B BF 8C
A2 33 90 2B 9A 82 C2 86 98 4B E0 00 00 03 03 E7
21 45 CA 65 B8 6E 54 27 21 BE 72 DD D9 06 E2 18
C2 BB BE 58 A9 87 6F E0 31 6D 4B 3F 4D C0 9E 90
57 6A 1A 0F F2 90 13 FE D0 25 E5 A9 B9 8C 6E 67
E5 8A 05 81 7F 5D 0E EE 54 E4 B2 32 C6 47 5C 26
FE FD 48 2B B5 07 97 F5 C9 FF 82 3F 0F 5D 60 CF
B0 3B 9C 6E EF 9F 5D 97 98 97 F3 C5 CF 32 AB BB
64 AB C3 C8 DE B8 A3 CF 95 08 D3 B9 BE F8 31 3F
54 C2 EE 14 3B DC C7 7F BE 94 37 FF 99 44 F4 4C
86 BD 1B 9F 89 2A EF 2E 62 99 4A CF 1B 18 26 90
*****

4byte    start: 00 00 01 E0
2byte    packlen: 13 FA    = 5114
2byte    packinfo: 8C 00
1byte    stufflen: 02
2byte    stuff: FF FD
4byte    start: 00 00 00 01
1byte    nalType: 65 --> I帧
5105byte nalBody: B8 00 *********

8.PES: I帧报文分片

00 00 01 E0 13 FA 88 00 02 FF FF 22 DC A8 84 12
A5 18 90 DB 76 92 7C 3D AD 70 91 54 39 71 00 31
17 06 81 1C 4C 15 38 78 5C 4B F0 D8 51 B2 89 7A
92 E1 09 1E AF 67 8B 18 C8 4D DA 3C 71 E7 6D 7A
B8 5B 4E EF 5B 4D 3B CB BA E8 F6 87 E3 9D E8 B8
26 C3 12 0A 41 F9 95 76 04 31 0A 64 43 D5 C0 CC
CC 96 7C 77 B6 64 25 58 65 2C 8A DC 61 FD FD 1D
93 86 FB 13 30 AE A0 A4 21 31 CE 93 3C FC 6C 39
57 FA 74 93 F0 E1 8C 7E 15 CD 63 10 AD 0A C9 66
7C 7B 69 3B BD 71 46 B5 C4 AA 60 61 53 E3 01 C2
F6 AF 52 42 41 DA E1 EE 25 F9 85 3A 95 9A 5E 5F
2B 0E F5 FB CB 98 FF 8C 2D 7E C1 78 6C 7F EE CF
F6 42 9C 17 F4 68 8F 1F 4E E5 60 05 F9 E2 77 28
08 39 3E 84 07 2E 77 BF FC 57 BB 2B 5E 41 35 0A
*****

4byte    start: 00 00 01 E0
2byte    packlen:13 FA = 5114
2byte    packinfo: 88 00
1byte    stufflen: 02      
2byte    stuff: FF FF
5109byte nalBody: 22 DC A7 ****

9.PES:P帧报文

00 00 01 E0 13 FA 8C 80 07 21 BE BF 20 31 FF FD
00 00 00 01 61 E0 08 87 7F FE 8C B3 83 77 DE EB
C5 C1 BA E2 7E 08 F9 00 29 A4 2A D5 BF 03 46 60
B6 79 5E EF A3 CF 7E 85 72 9B 0F 71 36 44 06 0C
5B CB 01 95 D9 77 B4 DB BD 7D 2F 9B 89 C9 EF 55
1A 7B 7D BD 02 AC F1 DD 9D 4F 9E 36 42 4B 34 74
EF 62 C1 24 E5 F8 B5 9C 11 DD E1 CA 59 FB B6 33
93 20 6A 0B 0B 28 18 21 A2 E6 97 A7 C1 A0 8C 53
95 72 F4 9C 93 0C 41 AC 4A AD 56 9F A5 40 F9 AF
57 20 37 46 45 B8 27 B7 B9 82 36 B5 0B A3 C1 06
*****

4byte    start: 00 00 01 E0
2byte    packlen: 13 FA    = 5114
2byte    packinfo: 8C 80
1byte    stufflen: 07
2byte    stuff: 21 BF BF 20 31 FF FD
4byte    start: 00 00 00 01
1byte    nalType: 61 --> 非I帧
5105byte nalBody: E0 08 *********

10.PES:音频报文ADTS。参考:https://blog.csdn.net/dreamInTheWorld/article/details/130600690

00 00 01 C0 00 C6 8C 80 09 2D 3E BF 77 71 FF FF
FF F8 FF F9 60 40 17 5F FC 01 38 32 AC 74 26 0D
0A 04 C2 40 B1 10 2C 14 0A 84 82 81 21 88 50 22
32 0A 84 C2 23 00 00 00 00 00 EF BC A3 BF B3 FD
7D D7 B3 07 F9 C8 C8 37 60 CC 72 47 AC 43 F8 AF
A0 B8 E2 F9 5B 59 F1 F2 6D CF B0 A8 90 90 A5 9B
3F E6 E7 71 25 AE 88 68 4F 0F 00 A6 38 8C D1 F4
EF 43 F4 FF AB D1 76 81 D4 3A A4 01 06 1C 7D DD
76 32 C2 7C 64 DB 8D FD 61 C5 76 2F D3 49 70 C2
7B DD 26 90 FE 1C A3 BA 3A ED 9D 5E D5 AA A5 C1
28 61 5C A3 07 33 3F 44 F1 67 2D CA C9 46 18 EE
AF A4 26 62 D8 21 61 6F 70 C8 70 C5 B1 15 50 86
B9 7F 86 68 08 91 40 08 80 99 B4 07 00 00 01 BA
46 FA FC 80 C4 01 00 00 03 FE FF FF 00 00 00 02

4byte    start: 00 00 01 C0
2byte    packlen: 00 C6 = 198
2byte    packinfo: 8C 80
1byte    stufflen: 09
9byte    stuff: 2D 3E BF 77 71 FF FF FF F8

ADTS_1:    FF F9 60 40

12bit:   syncword:    FF F

1bit:    id:    1001    MPEG Version: 0 --> MPEG-4; 1 --> MPEG-2

2bit:    layer:    1001     always: '00'

1bit:    protection+absent: 1001    标识是否进行误码校验。0 --> CRC校验; 1 --> 无校验

2bit:    profile:     0110     0 --> Main profile; 1 --> Low Complexity profile(LC); 2 --> Scalable Sampling Rate profile(SSR)

4bit:    sampling_frequency_index    0110 0000    0 --> 96000Hz; 4 --> 44100Hz; 8 --> 16000Hz; 11 --> 8000Hz    

1bit:    private_bit:    0000    私有位,编码

3bit:    channel_configuration:    0000 0100    单声道

1bit:    original_copy:    0100        编码时设置为0,解码时忽略

1bit:    home:    0100    编码时设置为0,解码时忽略

 

ADTS_2:   1C DF FC

1bit:    copyright_identification_bit:    0000 0001 1100 1101 1111 1111 1100    编码时设置为0,解码时忽略

1bit:     copyright_identification_bit:    0000 0001 1100 1101 1111 1111 1100    编码时设置为0,解码时忽略

13bit:    aac_frame_length:    0000 0001 1100 1101 1111 1111 1100  --> 230    ADTS帧长度:ADTS长度+AAC声音数据长度

11bit:    adts_buffer_fullness:    0000 0001 1100 1101 1111 1111 1100    固定为0x7FF    表示是码率可变的码流

2bit:     number_of_raw_data_blocks_in_frame:    0000 0001 1100 1101 1111 1111 1100    表示有number_of_raw_data_blocks_in_frame+1个原始帧
 

 

C++方式解析PS头,解析出音视频编码类型:

struct ps_head {
       unsigned char start_code[3];
       unsigned char stream_id[1];
       unsigned char marker[9];
       unsigned char stuffinglen;
};
struct program_stream
{
       unsigned char start_code[3];
       unsigned char stream_id[1];
       unsigned short packlen;
       unsigned char packinfo[2];
       unsigned short program_strem_info_len;
};
struct elementary_stream {
       unsigned char stream_type[1];
       unsigned char elementary_stream_id[1];
       unsigned short elementary_stream_info_len;
};

bool EhomeSDK::ParsePSHead(BYTE* pBuffer, int nBufLenth, AVCodecID& videoType,  AVCodecID& audioType)
{
     //unsigned char pBuffer[1024] = {
     //    0x00, 0x00, 0x01, 0xBA, 0x45, 0xEC, 0x36, 0x4E, 0xA4, 0x01, 0x00,  0x00, 0x03, 0xFE, 0xFF, 0xFF,
     //    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0xBC, 0x00, 0x5A, 0xE0,  0xFF, 0x00, 0x24, 0x40, 0x0E,
     //    0x48, 0x4B, 0x00, 0x00, 0x17, 0xA3, 0xB5, 0x98, 0xA0, 0x00, 0x00,  0xFF, 0xFF, 0xFF, 0x41, 0x12,
     //    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00,
     //    0x00, 0x00, 0x00, 0x2C, 0x1B, 0xE0, 0x00, 0x10, 0x42, 0x0E, 0x00,  0x00, 0xA0, 0x21, 0x05, 0x00,
     //    0x02, 0xD0, 0x12, 0x1C, 0x3F, 0x00, 0x1C, 0x21, 0x0F, 0xC0, 0x00,  0x0C, 0x43, 0x0A, 0x00, 0x00,
     //    0xFE, 0x00, 0xFA, 0x03, 0x01, 0xF4, 0x03, 0xFF, 0xBD, 0xBD, 0x00,  0x00, 0xBF, 0xBF, 0x00, 0x00,
     //    0x00, 0x00, 0x00, 0x00
     //};
    videoType = audioType = AV_CODEC_ID_NONE;
    int index = 0;
    ps_head* PSHead = (ps_head*)pBuffer;
    PSHead->stuffinglen = PSHead->stuffinglen & 0x07;
    index = sizeof(ps_head) + PSHead->stuffinglen;
    program_stream* PSProgrm = (program_stream*)(pBuffer + index);
    PSProgrm->packlen = ((PSProgrm->packlen & 0x0F) << 8) + (PSProgrm->packlen >>  8);
    PSProgrm->program_strem_info_len = ((PSProgrm->program_strem_info_len & 0x0F)  << 8) + (PSProgrm->program_strem_info_len >> 8);
    index = index + sizeof(program_stream) + PSProgrm->program_strem_info_len;
    index += 2;
    int elementary_stream_map_length = ((pBuffer[index] << 8) + pBuffer[index +  1]);
    while (index < nBufLenth) {
        elementary_stream* PSElementary = (elementary_stream*)(pBuffer + index);
        if (PSElementary->elementary_stream_id[0] == 0xE0) {
            if(PSElementary->stream_type[0] == 0x1B){
                videoType = AV_CODEC_ID_H264;
            }
            else if(PSElementary->stream_type[0] == 0x24){
                videoType = AV_CODEC_ID_H265;
            }
        }
        else if (PSElementary->elementary_stream_id[0] == 0xC0) {
            if(PSElementary->stream_type[0] == 0x0F){
                videoType = AV_CODEC_ID_AAC;
            }
            else if(PSElementary->stream_type[0] == 0x90){
                videoType = AV_CODEC_ID_PCM_ALAW;
            }
            audioType = PSElementary->stream_type[0];
        }
        else {
            break;
        }
        PSElementary->elementary_stream_info_len = ((PSElementary->elementary_stream_info_len & 0x0F) << 8) +  (PSElementary->elementary_stream_info_len >> 8);
        index = index + sizeof(elementary_stream) +  PSElementary->elementary_stream_info_len;
    }
    return true;
}

 

posted @ 2023-09-28 14:55  飞翔天空energy  阅读(1318)  评论(1编辑  收藏  举报