[Mediaserver]mini_Mediaserver_1-코드설명/code description-read_message_header()(1-4)

👉🏻 여기는 void RtmpSession::read_message_header(uint8_t fmt, uint32_t cs_id) { } 이 함수에 대한 설명입니다.
Here is the description for the function void RtmpSession::read_message_header(uint8_t fmt, uint32_t cs_id) { }.

👉🏻 OBS가 보낸 chunk에서 fmt 0∼3에 따라 가변 헤더를 읽고, 현재 메시지의 timestamp, length, type, stream_id를 갱신합니다.
Read variable headers according to fmt 0~3 from the chunk sent by OBS, and update the timestamp, length, type, and stream_id of the current message.

👉🏻 갱신이란 의미는 “멤버변수 4개를 다음 chunk 헤더에서 읽은 값으로 바꾸거나, delta(변화값)를 더해서 다음 메시지를 조립할 준비를 한다”는 뜻입니다.
Update means “prepare to assemble the next message by changing the four member variables to the values ​​read from the next chunk header or adding delta(change value).”


👉🏻 2비트로 표현 가능한 값 = 00, 01, 10, 11 = 10진수로 0, 1, 2, 3. 까지 가능합니다.
Values ​​that can be represented by 2 bits = 00, 01, 10, 11 = up to 0, 1, 2, 3 in decimal.

👉🏻 네트워크로 데이터 보내기(0x12345678)
Send data over network (0x12345678)

✔️ 1바이트씩 보낼 때
When sending 1 byte at a time

— 네트워크로 보낼 땐 무조건 uint8_t 배열, 즉 바이트 단위로 보내야 합니다.
When sending over a network, you must always send it as a uint8_t array, that is, in byte units.

uint8_t buf[4] = {0x12, 0x34, 0x56, 0x78};
send(socket, buf, 4); // 1바이트씩 4번 전송됨 / Transmitted 4 times, 1 byte at a time

✔️ 2바이트씩 보낼때(추천하지 않음)
When sending 2 bytes at a time (not recommended)

uint16_t buf[2] = {htons(0x1234), htons(0x5678)};
send(socket, buf, 4); // 12 34 56 78

👉🏻1바이트를 읽는 다는 의미는 소켓 버퍼에 들어온 실제 데이터(숫자)를 읽는 다는 뜻입니다.(포인터 주소랑 관련 없음)
Reading 1 byte means reading the actual data (number) that has entered the socket buffer. (It is not related to pointer addresses.)


👉🏻 fmt 값에 따른 헤드크기 설정 정보는 다음과 같습니다.
The head size setting information based on the fmt value is as follows.

✔️ 헤더 크기, 보내는 정보
Header size, information being sent

— msg_len은 실제로 보내지는 동영상 데이터 크기 입니다.
msg_len is the actual size of the video data being sent.

fmt이름
name
헤더 크기header size사용할때
When to use
보내는 정보
Sending information
0Type 011 byte새 메시지 시작
Start a new message
timestamp 3Byte
+ msg_len 3B
+ msg_type 1B
+ stream_id 4B
1Type 17 byte같은 stream_id, 타입만 이어서 보낼 때
When concatenating only stream_id and type
timestamp_delta(차이값/difference value) 3B
+ msg_len 3B + msg_type 1B
2Type 23 bytemsg_len, type 다 같고 시간만 바뀔 때
When msg_len and type are the same and only the time changes
timestamp_delta(차이값/diffrence value) 3B
3Type 30 byte헤더 전부 이전이랑 같을 때
When all headers are the same as before
아무것도 없음
nothing

✔️ 헤더 배열 / header array

fmt헤더 바이트 배열 / header byte array
0[TS0][TS1][TS2][Len0][Len1][Len2][Type][StreamID0∼3] = 11B
1[TS0][TS1][TS2][Len0][Len1][Len2][Type] = 7B
2[TS0][TS1][TS2] = 3B
3없음

✔️ 패킷에서 값을 확인 할때 헤더다음에 본문(payload)이 옵니다. 본문의 경계를 확인하기 위해서 헤더의 크기를 알아야할 필요가 있습니다.
When checking values ​​in a packet, the body (payload) follows the header. To check the boundaries of the body, it is necessary to know the size of the header.

✔️ 헤더사이즈가 0이면 read_chunk_data()를 실행합니다.
If header size is 0, execute read_chunk_data().

    size_t header_size = (fmt == 0)? 11 : (fmt == 1)? 7 : (fmt == 2)? 3 : 0;
    if (header_size == 0) {
        read_chunk_data();
        return;
    }

✔️ 헤더에 변화가 있는 경우,타임스탬프 조립
If there is a change in the header, timestamp assembly

— 그냥 [0],[1],[2]는 자릿수가 겹치지 않으므로 or 연산하면 그대로 내려옵니다.
Since [0], [1], and [2] do not have overlapping digits, they come down as they are when performing an OR operation.

     if (fmt <= 2) {
         // | 는 or연산 둘중 하나라도 1이면 1,아래는 셋중 하나라도 1이면 1
         // | is the OR operation; if at least one of the pairs is 1, the result is 1. The one below is 1 if at least one of the three is 1.
         timestamp = (msg_header_buf_[0] << 16) | 
                     (msg_header_buf_[1] << 8) |  
                      msg_header_buf_[2];          
                                                         
     }
# 01 E2 40 3바이트가 들어왔을 경우
# 01 E2 40 If 3 bytes are received

msg_header_buf_[0] = 0x01 = 00000001 = 1
msg_header_buf_[1] = 0xE2 = 11100010 = 226
msg_header_buf_[2] = 0x40 = 01000000 = 64

# 왼쪽으로 16비트 밀기
# Shift 16 bits to the left
(0x01 << 16) = 0x010000 = 00000001 00000000

# 왼쪽으로 8비트 밀기
# Shift 8 bits to the left
(0xE2 << 8) = 0x00E200 = 00000000 11100010 00000000

# 비트밀기 없음
# No beet milling
 0x40 = 0x000040 = 00000000 00000000 01000000

-------------------------------- OR 연산 / OR operation
               0x01E240 = 00000001 11100010 01000000 = 123456

✔️ 새 매세지 시작,확장 타임스템프 사용,동영상 크기
Start new message, use extended timestamp, video size

— 0xFFFFFF = 16,777,215 3바이트로 표현 가능한 최대값으로 확장 타임스탭프를 사용해야함을 의미합니다.
0xFFFFFF = 16,777,215, the maximum value that can be represented by 3 bytes, meaning that an extended timestamp must be used.

— 새 메세지 헤더 /New message header:

timestamp 3(0~2)Byte + msg_len 3(3~5)B + msg_type 1(6)B + extended timestamp 4(7~10)B + stream_id 4B

— msg_len은 이번에 보낼 FLV tag/Video frame/Audio packet 전체 크기입니다.
msg_len is the total size of the FLV tag/Video frame/Audio packet to be sent this time.

— cur_msg_stream_ 는 stream_id로 little endian으로 변환합니다.
cur_msg_stream_ converts to little endian with stream_id.

 if (fmt == 0) {

     cur_msg_timestamp_ = timestamp;
     // 0xFFFFFF = 16,777,215 3바이트로표현가능한 최대값,
     // 0xFFFFFF = 16,777,215, the maximum value that can be represented by 3 bytes
     // 확장필드 / extended field
     if (timestamp == 0xFFFFFF && header_size >= 11) {
        // use extended timestamp
        cur_msg_timestamp_ = (msg_header_buf_[7] << 24) |
                             (msg_header_buf_[8] << 16) |
                             (msg_header_buf_[9] << 8) |
                              msg_header_buf_[10];
      }
     // msg_len
     cur_msg_len_ = (msg_header_buf_[3] << 16) | 
                    (msg_header_buf_[4] << 8) | msg_header_buf_[5];
     // msg_type
     cur_msg_type_ = msg_header_buf_[6];
     // stream_id 
     // little endian으로 변환
     cur_msg_stream_ = msg_header_buf_[7] | 
                       (msg_header_buf_[8] << 8) |
                       (msg_header_buf_[9] << 16) | 
                       (msg_header_buf_[10] << 24);
     payload_buf_.clear();
     payload_bytes_read_ = 0;

— stream_id가 동일한 경우,timestamp 누적,기존 값은 동일합니다.
If stream_id is the same, timestamps accumulate, and existing values ​​are identical.

} else if (fmt == 1) {
           // timestamp 누적
           // timestamp cumulative
           cur_msg_timestamp_ += timestamp;

           // msg_len
           cur_msg_len_ = (msg_header_buf_[3] << 16) | 
                          (msg_header_buf_[4] << 8) | msg_header_buf_[5];
           // msg_type
           cur_msg_type_ = msg_header_buf_[6];
           payload_buf_.clear();
           payload_bytes_read_ = 0;

           // 나머지동일하고 시간만 바뀌는 경우
           // Cases where everything else is the same and only the time changes
} else if (fmt == 2) {
            cur_msg_timestamp_ += timestamp;
}

— read_chunk_data();를 실행합니다.
Execute read_chunk_data();

Execute read_chunk_data();

Leave a Reply