Initial setup for CLion
This commit is contained in:
367
MediaClient/rtp/h265_rtp_rx.cpp
Normal file
367
MediaClient/rtp/h265_rtp_rx.cpp
Normal file
@@ -0,0 +1,367 @@
|
||||
/***************************************************************************************
|
||||
*
|
||||
* 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-2024, 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 "h265_rtp_rx.h"
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void h265_save_parameters(H265RXI * p_rxi, uint8 * p_data, uint32 len)
|
||||
{
|
||||
uint8 nal_type = ((p_data[0] >> 1) & 0x3f);
|
||||
|
||||
if (nal_type == HEVC_NAL_VPS && p_rxi->param_sets.vps_len == 0)
|
||||
{
|
||||
if (len <= sizeof(p_rxi->param_sets.vps) - 4)
|
||||
{
|
||||
int offset = 0;
|
||||
|
||||
p_rxi->param_sets.vps[0] = 0;
|
||||
p_rxi->param_sets.vps[1] = 0;
|
||||
p_rxi->param_sets.vps[2] = 0;
|
||||
p_rxi->param_sets.vps[3] = 1;
|
||||
|
||||
offset = 4;
|
||||
|
||||
memcpy(p_rxi->param_sets.vps+offset, p_data, len);
|
||||
p_rxi->param_sets.vps_len = len+offset;
|
||||
}
|
||||
}
|
||||
else if (nal_type == HEVC_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 == HEVC_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 h265_handle_aggregated_packet(H265RXI * p_rxi, uint8 * p_data, int len)
|
||||
{
|
||||
uint8 *src = p_data;
|
||||
int src_len = len;
|
||||
int skip_between = p_rxi->rxf_don ? 1 : 0;
|
||||
|
||||
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)
|
||||
{
|
||||
h265_save_parameters(p_rxi, src, nal_size);
|
||||
|
||||
if (p_rxi->d_offset + nal_size + 4 >= p_rxi->buf_len)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
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 + skip_between;
|
||||
src_len -= nal_size + skip_between;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL h265_data_rx(H265RXI * p_rxi, uint8 * p_data, int len)
|
||||
{
|
||||
uint8 * headerStart = p_data;
|
||||
uint32 packetSize = len;
|
||||
uint32 numBytesToSkip;
|
||||
uint8 naluType;
|
||||
BOOL beginPacket = FALSE;
|
||||
BOOL endPacket = FALSE;
|
||||
|
||||
if (packetSize < 2)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (p_rxi->rtprxi.rxf_loss)
|
||||
{
|
||||
// Packet loss, discard the previously cached packets
|
||||
p_rxi->d_offset = 0;
|
||||
}
|
||||
|
||||
naluType = (headerStart[0] & 0x7E) >> 1;
|
||||
|
||||
switch (naluType)
|
||||
{
|
||||
case 48:
|
||||
{
|
||||
// Aggregation Packet (AP)
|
||||
// We skip over the 2-byte Payload Header, and the DONL header (if any).
|
||||
if (p_rxi->rxf_don)
|
||||
{
|
||||
if (packetSize < 4)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
numBytesToSkip = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
numBytesToSkip = 2;
|
||||
}
|
||||
|
||||
return h265_handle_aggregated_packet(p_rxi, p_data+numBytesToSkip, len-numBytesToSkip);
|
||||
}
|
||||
|
||||
case 49:
|
||||
{
|
||||
// Fragmentation Unit (FU)
|
||||
// This NALU begins with the 2-byte Payload Header, the 1-byte FU header, and (optionally)
|
||||
// the 2-byte DONL header.
|
||||
// If the start bit is set, we reconstruct the original NAL header at the end of these
|
||||
// 3 (or 5) bytes, and skip over the first 1 (or 3) bytes.
|
||||
|
||||
if (packetSize < 3)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
uint8 startBit = headerStart[2] & 0x80; // from the FU header
|
||||
uint8 endBit = headerStart[2] & 0x40; // from the FU header
|
||||
if (startBit)
|
||||
{
|
||||
beginPacket = TRUE;
|
||||
|
||||
uint8 nal_unit_type = headerStart[2] & 0x3F; // the last 6 bits of the FU header
|
||||
uint8 newNALHeader[2];
|
||||
|
||||
newNALHeader[0] = (headerStart[0] & 0x81) | (nal_unit_type << 1);
|
||||
newNALHeader[1] = headerStart[1];
|
||||
|
||||
if (p_rxi->rxf_don)
|
||||
{
|
||||
if (packetSize < 5)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
headerStart[3] = newNALHeader[0];
|
||||
headerStart[4] = newNALHeader[1];
|
||||
numBytesToSkip = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
headerStart[1] = newNALHeader[0];
|
||||
headerStart[2] = newNALHeader[1];
|
||||
numBytesToSkip = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The start bit is not set, so we skip over all headers:
|
||||
beginPacket = FALSE;
|
||||
|
||||
if (p_rxi->rxf_don)
|
||||
{
|
||||
if (packetSize < 5)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
numBytesToSkip = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
numBytesToSkip = 3;
|
||||
}
|
||||
}
|
||||
|
||||
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 H265 parameter sets
|
||||
|
||||
h265_save_parameters(p_rxi, headerStart + numBytesToSkip, packetSize - numBytesToSkip);
|
||||
|
||||
if ((p_rxi->d_offset + 4 + packetSize - numBytesToSkip) >= p_rxi->buf_len)
|
||||
{
|
||||
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 (beginPacket)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
memcpy(p_rxi->p_buf + p_rxi->d_offset, headerStart + numBytesToSkip, packetSize - numBytesToSkip);
|
||||
p_rxi->d_offset += packetSize - numBytesToSkip;
|
||||
|
||||
if (endPacket && p_rxi->rtprxi.rxf_marker)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL h265_rtp_rx(H265RXI * 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 h265_data_rx(p_rxi, p_rxi->rtprxi.p_data, p_rxi->rtprxi.len);
|
||||
}
|
||||
|
||||
BOOL h265_rxi_init(H265RXI * p_rxi, VRTPRXCBF cbf, void * p_userdata)
|
||||
{
|
||||
memset(p_rxi, 0, sizeof(H265RXI));
|
||||
|
||||
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 h265_rxi_deinit(H265RXI * p_rxi)
|
||||
{
|
||||
if (p_rxi->p_buf_org)
|
||||
{
|
||||
free(p_rxi->p_buf_org);
|
||||
}
|
||||
|
||||
memset(p_rxi, 0, sizeof(H265RXI));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user