Files
gb28181/GB28181Device/rtp/h264_rtp_rx.cpp
2024-12-15 20:42:32 +08:00

367 lines
9.5 KiB
C++

/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2022, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#include "sys_inc.h"
#include "rtp.h"
#include "h264_rtp_rx.h"
/***********************************************************************/
void h264_save_parameters(H264RXI * p_rxi, uint8 * p_data, uint32 len)
{
uint8 nal_type = (p_data[0] & 0x1F);
if (nal_type == H264_NAL_SPS && p_rxi->param_sets.sps_len == 0)
{
if (len <= sizeof(p_rxi->param_sets.sps) - 4)
{
int offset = 0;
p_rxi->param_sets.sps[0] = 0;
p_rxi->param_sets.sps[1] = 0;
p_rxi->param_sets.sps[2] = 0;
p_rxi->param_sets.sps[3] = 1;
offset = 4;
memcpy(p_rxi->param_sets.sps+offset, p_data, len);
p_rxi->param_sets.sps_len = len+offset;
}
}
else if (nal_type == H264_NAL_PPS && p_rxi->param_sets.pps_len == 0)
{
if (len <= sizeof(p_rxi->param_sets.pps) - 4)
{
int offset = 0;
p_rxi->param_sets.pps[0] = 0;
p_rxi->param_sets.pps[1] = 0;
p_rxi->param_sets.pps[2] = 0;
p_rxi->param_sets.pps[3] = 1;
offset = 4;
memcpy(p_rxi->param_sets.pps+offset, p_data, len);
p_rxi->param_sets.pps_len = len+offset;
}
}
}
BOOL h264_handle_aggregated_packet(H264RXI * p_rxi, uint8 * p_data, int len)
{
uint8 *src = p_data;
int src_len = len;
while (src_len > 2)
{
uint16 nal_size = ((src[0] << 8) | src[1]);
// consume the length of the aggregate
src += 2;
src_len -= 2;
if (nal_size <= src_len)
{
h264_save_parameters(p_rxi, src, nal_size);
if ((p_rxi->d_offset + nal_size + 4) >= RTP_MAX_VIDEO_BUFF)
{
if (p_rxi->rtprxi.rxf_marker)
{
p_rxi->d_offset = 0;
}
log_print(HT_LOG_ERR, "%s, packet too big %d!!!", __FUNCTION__, p_rxi->d_offset + nal_size + 4);
return FALSE;
}
else
{
p_rxi->p_buf[p_rxi->d_offset+0] = 0;
p_rxi->p_buf[p_rxi->d_offset+1] = 0;
p_rxi->p_buf[p_rxi->d_offset+2] = 0;
p_rxi->p_buf[p_rxi->d_offset+3] = 1;
p_rxi->d_offset += 4;
// copying
memcpy(p_rxi->p_buf + p_rxi->d_offset, src, nal_size);
p_rxi->d_offset += nal_size;
if (p_rxi->pkt_func)
{
p_rxi->pkt_func(p_rxi->p_buf, p_rxi->d_offset, p_rxi->rtprxi.ts, p_rxi->rtprxi.seq, p_rxi->user_data);
p_rxi->d_offset = 0;
}
}
}
else
{
log_print(HT_LOG_ERR, "%s, nal size exceeds length: %d %d\n", __FUNCTION__, nal_size, src_len);
return FALSE;
}
// eat what we handled
src += nal_size;
src_len -= nal_size;
}
return TRUE;
}
BOOL h264_data_rx(H264RXI * p_rxi, uint8 * p_data, int len)
{
uint8 * headerStart = p_data;
uint32 packetSize = len;
uint32 numBytesToSkip;
uint8 naluType;
BOOL beginPacket = FALSE;
BOOL endPacket = FALSE;
// Check the 'nal_unit_type' for special 'aggregation' or 'fragmentation' packets
if (packetSize < 1)
{
return FALSE;
}
if (p_rxi->rtprxi.rxf_loss)
{
if (p_rxi->full_pkt)
{
if (p_rxi->pkt_func && p_rxi->d_offset > 0)
{
p_rxi->p_buf[0] = 0;
p_rxi->p_buf[1] = 0;
p_rxi->p_buf[2] = 0;
p_rxi->p_buf[3] = 1;
p_rxi->d_offset += 4;
p_rxi->pkt_func(p_rxi->p_buf, p_rxi->d_offset, p_rxi->pkt_ts, p_rxi->pkt_seq, p_rxi->user_data);
}
}
// Packet loss, discard the previously cached packets
p_rxi->d_offset = 0;
p_rxi->full_pkt = 0;
}
naluType = (headerStart[0] & 0x1F);
switch (naluType)
{
case 24: // STAP-A
numBytesToSkip = 1; // discard the type byte
return h264_handle_aggregated_packet(p_rxi, p_data+numBytesToSkip, len-numBytesToSkip);
case 25: case 26: case 27: // STAP-B, MTAP16, or MTAP24
numBytesToSkip = 3; // discard the type byte, and the initial DON
break;
case 28: case 29: // FU-A or FU-B
{
// For these NALUs, the first two bytes are the FU indicator and the FU header.
// If the start bit is set, we reconstruct the original NAL header into byte 1
if (packetSize < 2)
{
return FALSE;
}
uint8 startBit = headerStart[1] & 0x80;
uint8 endBit = headerStart[1] & 0x40;
if (startBit)
{
beginPacket = TRUE;
headerStart[1] = (headerStart[0] & 0xE0) | (headerStart[1] & 0x1F);
numBytesToSkip = 1;
}
else
{
// The start bit is not set, so we skip both the FU indicator and header:
beginPacket = FALSE;
numBytesToSkip = 2;
}
endPacket = (endBit != 0);
break;
}
default:
// This packet contains one complete NAL unit:
beginPacket = endPacket = TRUE;
numBytesToSkip = 0;
break;
}
if (p_rxi->rtprxi.rxf_loss)
{
// Packet loss, until the next start packet
if (!beginPacket)
{
return FALSE;
}
else
{
p_rxi->rtprxi.rxf_loss = 0;
}
}
// save the H264 parameter sets
h264_save_parameters(p_rxi, headerStart + numBytesToSkip, packetSize - numBytesToSkip);
if ((p_rxi->d_offset + 4 + packetSize - numBytesToSkip) >= RTP_MAX_VIDEO_BUFF)
{
if (p_rxi->rtprxi.rxf_marker)
{
p_rxi->d_offset = 0;
}
log_print(HT_LOG_ERR, "%s, fragment packet too big %d!!!", __FUNCTION__, p_rxi->d_offset + 4 + packetSize - numBytesToSkip);
return FALSE;
}
if (p_rxi->full_pkt && p_rxi->pkt_ts != p_rxi->rtprxi.ts)
{
// The previous packet has formed a complete frame
if (p_rxi->pkt_func)
{
p_rxi->p_buf[0] = 0;
p_rxi->p_buf[1] = 0;
p_rxi->p_buf[2] = 0;
p_rxi->p_buf[3] = 1;
p_rxi->d_offset += 4;
p_rxi->pkt_func(p_rxi->p_buf, p_rxi->d_offset, p_rxi->pkt_ts, p_rxi->pkt_seq, p_rxi->user_data);
}
p_rxi->d_offset = 0;
p_rxi->full_pkt = 0;
}
else if (p_rxi->full_pkt && p_rxi->pkt_ts == p_rxi->rtprxi.ts && beginPacket)
{
uint8 nalu1 = headerStart[numBytesToSkip] & 0x1F;
uint8 nalu2 = p_rxi->p_buf[4] & 0x1F;
if (p_rxi->multi_slice && nalu1 == nalu2)
{
// Same as the timestamp, it should be a multi slices frame
p_rxi->p_buf[p_rxi->d_offset + 4 + 0] = 0;
p_rxi->p_buf[p_rxi->d_offset + 4 + 1] = 0;
p_rxi->p_buf[p_rxi->d_offset + 4 + 2] = 1;
p_rxi->d_offset += 3;
}
else if (nalu1 == 5 && nalu1 == nalu2)
{
// Same as the timestamp, it should be a multi slices frame
p_rxi->p_buf[p_rxi->d_offset + 4 + 0] = 0;
p_rxi->p_buf[p_rxi->d_offset + 4 + 1] = 0;
p_rxi->p_buf[p_rxi->d_offset + 4 + 2] = 1;
p_rxi->d_offset += 3;
p_rxi->multi_slice = 1;
}
else
{
if (p_rxi->pkt_func)
{
p_rxi->p_buf[0] = 0;
p_rxi->p_buf[1] = 0;
p_rxi->p_buf[2] = 0;
p_rxi->p_buf[3] = 1;
p_rxi->d_offset += 4;
p_rxi->pkt_func(p_rxi->p_buf, p_rxi->d_offset, p_rxi->pkt_ts, p_rxi->pkt_seq, p_rxi->user_data);
}
p_rxi->d_offset = 0;
p_rxi->full_pkt = 0;
}
}
memcpy(p_rxi->p_buf + p_rxi->d_offset + 4, headerStart + numBytesToSkip, packetSize - numBytesToSkip);
p_rxi->d_offset += packetSize - numBytesToSkip;
if (endPacket)
{
// Do not submit, wait for the next packet to
// determine whether it is a multi slices frame
p_rxi->full_pkt = 1;
p_rxi->pkt_ts = p_rxi->rtprxi.ts;
p_rxi->pkt_seq = p_rxi->rtprxi.seq;
}
return TRUE;
}
BOOL h264_rtp_rx(H264RXI * p_rxi, uint8 * p_data, int len)
{
if (p_rxi == NULL)
{
return FALSE;
}
if (!rtp_data_rx(&p_rxi->rtprxi, p_data, len))
{
return FALSE;
}
return h264_data_rx(p_rxi, p_rxi->rtprxi.p_data, p_rxi->rtprxi.len);
}
BOOL h264_rxi_init(H264RXI * p_rxi, VRTPRXCBF cbf, void * p_userdata)
{
memset(p_rxi, 0, sizeof(H264RXI));
p_rxi->buf_len = RTP_MAX_VIDEO_BUFF;
p_rxi->p_buf_org = (uint8 *)malloc(p_rxi->buf_len);
if (p_rxi->p_buf_org == NULL)
{
return -1;
}
p_rxi->p_buf = p_rxi->p_buf_org + 32;
p_rxi->buf_len -= 32;
p_rxi->pkt_func = cbf;
p_rxi->user_data = p_userdata;
return 0;
}
void h264_rxi_deinit(H264RXI * p_rxi)
{
if (p_rxi->p_buf_org)
{
free(p_rxi->p_buf_org);
}
memset(p_rxi, 0, sizeof(H264RXI));
}