Initial setup for CLion

This commit is contained in:
2026-03-28 16:54:11 +11:00
parent 239cc02591
commit 7b4134133c
1136 changed files with 811916 additions and 0 deletions

View File

@@ -0,0 +1,206 @@
/***************************************************************************************
*
* 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 "aac_rtp_rx.h"
#include "bs.h"
BOOL aac_data_rx(AACRXI * p_rxi, uint8 * p_data, int len)
{
struct AUHeader
{
uint32 size;
uint32 index; // indexDelta for the 2nd & subsequent headers
};
uint8* headerStart = p_data;
uint32 packetSize = len;
uint32 resultSpecialHeaderSize;
uint32 fNumAUHeaders; // in the most recently read packet
struct AUHeader* fAUHeaders;
// default values:
resultSpecialHeaderSize = 0;
fNumAUHeaders = 0;
fAUHeaders = NULL;
if (p_rxi->size_length == 0)
{
return FALSE;
}
// The packet begins with a "AU Header Section". Parse it, to
// determine the "AU-header"s for each frame present in this packet
resultSpecialHeaderSize += 2;
if (packetSize < resultSpecialHeaderSize)
{
return FALSE;
}
uint32 AU_headers_length = (headerStart[0] << 8) | headerStart[1];
uint32 AU_headers_length_bytes = (AU_headers_length + 7) / 8;
if (packetSize < resultSpecialHeaderSize + AU_headers_length_bytes)
{
return FALSE;
}
resultSpecialHeaderSize += AU_headers_length_bytes;
// Figure out how many AU-headers are present in the packet
int bitsAvail = AU_headers_length - (p_rxi->size_length + p_rxi->index_length);
if (bitsAvail >= 0 && (p_rxi->size_length + p_rxi->index_delta_length) > 0)
{
fNumAUHeaders = 1 + bitsAvail / (p_rxi->size_length + p_rxi->index_delta_length);
}
if (fNumAUHeaders > 0)
{
fAUHeaders = new AUHeader[fNumAUHeaders];
// Fill in each header:
bs_t bs;
bs_init(&bs, &headerStart[2], AU_headers_length);
fAUHeaders[0].size = bs_read(&bs, p_rxi->size_length);
fAUHeaders[0].index = bs_read(&bs, p_rxi->index_length);
for (uint32 i = 1; i < fNumAUHeaders; ++i)
{
fAUHeaders[i].size = bs_read(&bs, p_rxi->size_length);
fAUHeaders[i].index = bs_read(&bs, p_rxi->index_delta_length);
}
}
p_data += resultSpecialHeaderSize;
len -= resultSpecialHeaderSize;
if (fNumAUHeaders == 1 && (uint32) len < fAUHeaders[0].size)
{
if (fAUHeaders[0].size > p_rxi->buf_len)
{
if (fAUHeaders)
{
delete[] fAUHeaders;
}
return FALSE;
}
memcpy(p_rxi->p_buf + p_rxi->d_offset, p_data, len);
p_rxi->d_offset += len;
if (p_rxi->rtprxi.rxf_marker)
{
if (p_rxi->d_offset != fAUHeaders[0].size)
{
if (fAUHeaders)
{
delete[] fAUHeaders;
}
p_rxi->d_offset = 0;
return FALSE;
}
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);
}
}
}
else
{
for (uint32 i = 0; i < fNumAUHeaders; i++)
{
if ((uint32) len < fAUHeaders[i].size)
{
if (fAUHeaders)
{
delete[] fAUHeaders;
}
return FALSE;
}
memcpy(p_rxi->p_buf, p_data, fAUHeaders[i].size);
p_data += fAUHeaders[i].size;
len -= fAUHeaders[i].size;
if (p_rxi->pkt_func)
{
p_rxi->pkt_func(p_rxi->p_buf, fAUHeaders[i].size, p_rxi->rtprxi.ts, p_rxi->rtprxi.seq, p_rxi->user_data);
}
}
}
if (fAUHeaders)
{
delete[] fAUHeaders;
}
return TRUE;
}
BOOL aac_rtp_rx(AACRXI * 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 aac_data_rx(p_rxi, p_rxi->rtprxi.p_data, p_rxi->rtprxi.len);
}
BOOL aac_rxi_init(AACRXI * p_rxi, VRTPRXCBF cbf, void * p_userdata)
{
memset(p_rxi, 0, sizeof(AACRXI));
p_rxi->buf_len = RTP_MAX_AUDIO_BUFF;
p_rxi->p_buf_org = (uint8 *)malloc(p_rxi->buf_len);
if (p_rxi->p_buf_org == NULL)
{
return FALSE;
}
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 TRUE;
}
void aac_rxi_deinit(AACRXI * p_rxi)
{
if (p_rxi->p_buf_org)
{
free(p_rxi->p_buf_org);
}
memset(p_rxi, 0, sizeof(AACRXI));
}

View File

@@ -0,0 +1,59 @@
/***************************************************************************************
*
* 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.
*
****************************************************************************************/
#ifndef AAC_RTP_RX_H
#define AAC_RTP_RX_H
#include "rtp_rx.h"
typedef struct aac_rtp_rx_info
{
RTPRXI rtprxi;
uint8 * p_buf_org; // Allocated buffer
uint8 * p_buf; // = p_buf_org + 32
uint32 buf_len; // Buffer length -32
uint32 d_offset; // Data offset
VRTPRXCBF pkt_func; // callback function
void * user_data; // user data
int size_length;
int index_length;
int index_delta_length;
} AACRXI;
#ifdef __cplusplus
extern "C" {
#endif
BOOL aac_data_rx(AACRXI * p_rxi, uint8 * p_data, int len);
BOOL aac_rtp_rx(AACRXI * p_rxi, uint8 * p_data, int len);
BOOL aac_rxi_init(AACRXI * p_rxi, VRTPRXCBF cbf, void * p_userdata);
void aac_rxi_deinit(AACRXI * p_rxi);
#ifdef __cplusplus
}
#endif
#endif

382
MediaClient/rtp/bs.h Normal file
View File

@@ -0,0 +1,382 @@
#ifdef BS_H
#warning FIXME Multiple inclusion of bs.h
#else
#define BS_H
typedef struct bs_s
{
uint8 * p_start;
uint8 * p;
uint8 * p_end;
int i_left; /* i_count number of available bits */
} bs_t;
static inline void bs_init(bs_t *s, void *p_data, int i_data)
{
s->p_start = (uint8 *)p_data;
s->p = (uint8 *)p_data;
s->p_end = s->p + i_data;
s->i_left = 8;
}
static inline int bs_pos(bs_t *s)
{
return (int)(8 * (s->p - s->p_start) + 8 - s->i_left);
}
static inline int bs_left(bs_t *s)
{
return (int)(8 * (s->p_end - s->p) + 8 - s->i_left);
}
static inline int bs_eof(bs_t *s)
{
return (s->p >= s->p_end ? 1: 0);
}
static inline uint32 bs_read(bs_t *s, int i_count)
{
static uint32 i_mask[33] = { 0x00,
0x01, 0x03, 0x07, 0x0f,
0x1f, 0x3f, 0x7f, 0xff,
0x1ff, 0x3ff, 0x7ff, 0xfff,
0x1fff, 0x3fff, 0x7fff, 0xffff,
0x1ffff, 0x3ffff, 0x7ffff, 0xfffff,
0x1fffff, 0x3fffff, 0x7fffff, 0xffffff,
0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff,
0x1fffffff,0x3fffffff,0x7fffffff,0xffffffff};
int i_shr;
uint32 i_result = 0;
while (i_count > 0)
{
if (s->p >= s->p_end)
{
break;
}
if ((i_shr = s->i_left - i_count) >= 0)
{
/* more in the buffer than requested */
i_result |= (*s->p >> i_shr)&i_mask[i_count];
s->i_left -= i_count;
if (s->i_left == 0)
{
s->p++;
s->i_left = 8;
}
return i_result;
}
else
{
/* less in the buffer than requested */
i_result |= (*s->p&i_mask[s->i_left]) << -i_shr;
i_count -= s->i_left;
s->p++;
s->i_left = 8;
}
}
return i_result;
}
static inline uint32 bs_read1(bs_t *s)
{
if (s->p < s->p_end)
{
uint32 i_result;
s->i_left--;
i_result = (*s->p >> s->i_left)&0x01;
if (s->i_left == 0)
{
s->p++;
s->i_left = 8;
}
return i_result;
}
return 0;
}
static inline uint32 bs_show(bs_t *s, int i_count)
{
if (s->p < s->p_end && i_count > 0)
{
uint32 i_cache = ((s->p[0] << 24)+(s->p[1] << 16)+(s->p[2] << 8)+s->p[3]) << (8-s->i_left);
return (i_cache >> (32 - i_count));
}
return 0;
}
/* TODO optimize */
static inline void bs_skip(bs_t *s, int i_count)
{
s->i_left -= i_count;
while (s->i_left <= 0)
{
s->p++;
s->i_left += 8;
}
}
static inline int bs_read_ue(bs_t *s)
{
int i = 0;
while (bs_read1(s) == 0 && s->p < s->p_end && i < 32)
{
i++;
}
return ((1 << i) - 1 + bs_read(s, i));
}
static inline int bs_read_se(bs_t *s)
{
int val = bs_read_ue(s);
return val&0x01 ? (val+1)/2 : -(val/2);
}
static inline int bs_read_te(bs_t *s, int x)
{
if (x == 1)
{
return 1 - bs_read1(s);
}
else if (x > 1)
{
return bs_read_ue(s);
}
return 0;
}
/* TODO optimize (write x bits at once) */
static inline void bs_write(bs_t *s, int i_count, uint32 i_bits)
{
while (i_count > 0)
{
if (s->p >= s->p_end)
{
break;
}
i_count--;
if ((i_bits >> i_count) & 0x01)
{
*s->p |= 1 << (s->i_left - 1);
}
else
{
*s->p &= ~(1 << (s->i_left - 1));
}
s->i_left--;
if (s->i_left == 0)
{
s->p++;
s->i_left = 8;
}
}
}
static inline void bs_write1(bs_t *s, uint32 i_bits)
{
if (s->p < s->p_end)
{
s->i_left--;
if (i_bits & 0x01)
{
*s->p |= 1 << s->i_left;
}
else
{
*s->p &= ~(1 << s->i_left);
}
if (s->i_left == 0)
{
s->p++;
s->i_left = 8;
}
}
}
static inline void bs_align(bs_t *s)
{
if (s->i_left != 8)
{
s->i_left = 8;
s->p++;
}
}
static inline void bs_align_0(bs_t *s)
{
if (s->i_left != 8)
{
bs_write(s, s->i_left, 0);
}
}
static inline void bs_align_1(bs_t *s)
{
if (s->i_left != 8)
{
bs_write(s, s->i_left, ~0);
}
}
/* golomb functions */
static inline void bs_write_ue(bs_t *s, uint32 val)
{
int i_size = 0;
static const int i_size0_255[256] =
{
1,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
};
if (val == 0)
{
bs_write(s, 1, 1);
}
else
{
uint32 tmp = ++val;
if (tmp >= 0x00010000)
{
i_size += 16;
tmp >>= 16;
}
if (tmp >= 0x100)
{
i_size += 8;
tmp >>= 8;
}
i_size += i_size0_255[tmp];
bs_write(s, 2 * i_size - 1, val);
}
}
static inline void bs_write_se(bs_t *s, int val)
{
bs_write_ue(s, val <= 0 ? -val * 2 : val * 2 - 1);
}
static inline void bs_write_te(bs_t *s, int x, int val)
{
if (x == 1)
{
bs_write(s, 1, ~val);
}
else if (x > 1)
{
bs_write_ue(s, val);
}
}
static inline void bs_rbsp_trailing(bs_t *s)
{
bs_write(s, 1, 1);
if (s->i_left != 8)
{
bs_write(s, s->i_left, 0x00);
}
}
static inline int bs_size_ue(uint32 val)
{
static const int i_size0_254[255] =
{
1, 3, 3, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
11,11,11,11,11,11,11,11,11,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
13,13,13,13,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15
};
if (val < 255)
{
return i_size0_254[val];
}
else
{
int i_size = 0;
val++;
if (val >= 0x10000)
{
i_size += 32;
val = (val >> 16) - 1;
}
if (val >= 0x100)
{
i_size += 16;
val = (val >> 8) - 1;
}
return i_size0_254[val] + i_size;
}
}
static inline int bs_size_se(int val)
{
return bs_size_ue(val <= 0 ? -val * 2 : val * 2 - 1);
}
static inline int bs_size_te(int x, int val)
{
if (x == 1)
{
return 1;
}
else if (x > 1)
{
return bs_size_ue(val);
}
return 0;
}
static inline uint8 * bs_data(bs_t *s)
{
return s->p - (8 - s->i_left) / 8;
}
#endif

56
MediaClient/rtp/h264.h Normal file
View File

@@ -0,0 +1,56 @@
/***************************************************************************************
*
* 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.
*
****************************************************************************************/
#ifndef H264_H
#define H264_H
/* NAL unit types */
enum
{
H264_NAL_SLICE = 1,
H264_NAL_DPA = 2,
H264_NAL_DPB = 3,
H264_NAL_DPC = 4,
H264_NAL_IDR = 5,
H264_NAL_SEI = 6,
H264_NAL_SPS = 7,
H264_NAL_PPS = 8,
H264_NAL_AUD = 9,
H264_NAL_END_SEQUENCE = 10,
H264_NAL_END_STREAM = 11,
H264_NAL_FILLER_DATA = 12,
H264_NAL_SPS_EXT = 13,
H264_NAL_AUXILIARY_SLICE = 19,
};
typedef struct
{
uint8 sps[256];
int sps_len;
uint8 pps[256];
int pps_len;
} H264ParamSets;
#endif

View File

@@ -0,0 +1,299 @@
/***************************************************************************************
*
* 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 "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 >= 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;
src_len -= 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;
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;
if (packetSize < 1)
{
return FALSE;
}
if (p_rxi->rtprxi.rxf_loss)
{
// Packet loss, discard the previously cached packets
p_rxi->d_offset = 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) >= 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 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));
}

View File

@@ -0,0 +1,59 @@
/***************************************************************************************
*
* 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.
*
****************************************************************************************/
#ifndef H264_RTP_RX_H
#define H264_RTP_RX_H
#include "h264.h"
#include "rtp_rx.h"
typedef struct h264_rtp_rx_info
{
RTPRXI rtprxi;
uint8 * p_buf_org; // Allocated buffer
uint8 * p_buf; // = p_buf_org + 32
uint32 buf_len; // Buffer length -32
uint32 d_offset; // Data offset
VRTPRXCBF pkt_func; // callback function
void * user_data; // user data
H264ParamSets param_sets; // h264 sps pps parameter sets
} H264RXI;
#ifdef __cplusplus
extern "C" {
#endif
BOOL h264_data_rx(H264RXI * p_rxi, uint8 * p_data, int len);
BOOL h264_rtp_rx(H264RXI * p_rxi, uint8 * p_data, int len);
BOOL h264_rxi_init(H264RXI * p_rxi, VRTPRXCBF cbf, void * p_userdata);
void h264_rxi_deinit(H264RXI * p_rxi);
#ifdef __cplusplus
}
#endif
#endif // H264_RTP_RX_H

View File

@@ -0,0 +1,235 @@
/***************************************************************************************
*
* 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 "bs.h"
#include "h264.h"
#include "h264_util.h"
void h264_parser_init(h264_t * h)
{
h->i_width = 0;
h->i_height = 0;
h->b_key = 0;
h->i_nal_type = -1;
h->i_ref_idc = -1;
h->i_idr_pic_id = -1;
h->i_frame_num = -1;
h->i_log2_max_frame_num = 0;
h->i_poc = -1;
h->i_poc_type = -1;
}
void h264_parser_parse(h264_t * h, nal_t * nal, int * pb_nal_start)
{
bs_t s;
*pb_nal_start = 0;
if (nal->i_type == H264_NAL_SPS || nal->i_type == H264_NAL_PPS)
{
*pb_nal_start = 1;
}
bs_init(&s, nal->p_payload, nal->i_payload);
if (nal->i_type == H264_NAL_SPS)
{
int i_tmp;
i_tmp = bs_read(&s, 8);
bs_skip(&s, 1+1+1 + 5 + 8);
/* sps id */
bs_read_ue(&s);
if (i_tmp >= 100)
{
bs_read_ue(&s); // chroma_format_idc
bs_read_ue(&s); // bit_depth_luma_minus8
bs_read_ue(&s); // bit_depth_chroma_minus8
bs_skip(&s, 1); // qpprime_y_zero_transform_bypass_flag
if (bs_read(&s, 1)) // seq_scaling_matrix_present_flag
{
int i, j;
for (i = 0; i < 8; i++)
{
if (bs_read(&s, 1)) // seq_scaling_list_present_flag[i]
{
uint8 i_tmp = 8;
for (j = 0; j < (i<6?16:64); j++)
{
i_tmp += bs_read_se(&s);
if (i_tmp == 0)
{
break;
}
}
}
}
}
}
/* Skip i_log2_max_frame_num */
h->i_log2_max_frame_num = bs_read_ue(&s) + 4;
/* Read poc_type */
h->i_poc_type = bs_read_ue(&s);
if (h->i_poc_type == 0)
{
h->i_log2_max_poc_lsb = bs_read_ue(&s) + 4;
}
else if (h->i_poc_type == 1)
{
int i_cycle;
/* skip b_delta_pic_order_always_zero */
bs_skip(&s, 1);
/* skip i_offset_for_non_ref_pic */
bs_read_se(&s);
/* skip i_offset_for_top_to_bottom_field */
bs_read_se(&s);
/* read i_num_ref_frames_in_poc_cycle */
i_cycle = bs_read_ue(&s);
if (i_cycle > 256)
{
i_cycle = 256;
}
while (i_cycle > 0)
{
/* skip i_offset_for_ref_frame */
bs_read_se(&s);
i_cycle--;
}
}
/* i_num_ref_frames */
bs_read_ue(&s);
/* b_gaps_in_frame_num_value_allowed */
bs_skip(&s, 1);
/* Read size */
h->i_width = 16 * (bs_read_ue( &s ) + 1);
h->i_height = 16 * (bs_read_ue( &s ) + 1);
/* b_frame_mbs_only */
i_tmp = bs_read(&s, 1);
if (i_tmp == 0)
{
bs_skip(&s, 1);
}
/* b_direct8x8_inference */
bs_skip(&s, 1);
/* crop ? */
i_tmp = bs_read(&s, 1);
if (i_tmp)
{
/* left */
h->i_width -= 2 * bs_read_ue(&s);
/* right */
h->i_width -= 2 * bs_read_ue(&s);
/* top */
h->i_height -= 2 * bs_read_ue(&s);
/* bottom */
h->i_height -= 2 * bs_read_ue(&s);
}
/* vui: ignored */
}
else if (nal->i_type >= H264_NAL_SLICE && nal->i_type <= H264_NAL_IDR)
{
int i_tmp;
/* i_first_mb */
bs_read_ue(&s);
/* picture type */
switch (bs_read_ue(&s))
{
case 0: case 5: /* P */
case 1: case 6: /* B */
case 3: case 8: /* SP */
h->b_key = 0;
break;
case 2: case 7: /* I */
case 4: case 9: /* SI */
h->b_key = (nal->i_type == H264_NAL_IDR);
break;
}
/* pps id */
bs_read_ue(&s);
/* frame num */
i_tmp = bs_read(&s, h->i_log2_max_frame_num);
if (i_tmp != h->i_frame_num)
{
*pb_nal_start = 1;
}
h->i_frame_num = i_tmp;
if (nal->i_type == H264_NAL_IDR)
{
i_tmp = bs_read_ue(&s);
if (h->i_nal_type == H264_NAL_IDR && h->i_idr_pic_id != i_tmp)
{
*pb_nal_start = 1;
}
h->i_idr_pic_id = i_tmp;
}
if (h->i_poc_type == 0)
{
i_tmp = bs_read(&s, h->i_log2_max_poc_lsb);
if (i_tmp != h->i_poc)
{
*pb_nal_start = 1;
}
h->i_poc = i_tmp;
}
}
h->i_nal_type = nal->i_type;
h->i_ref_idc = nal->i_ref_idc;
}

View File

@@ -0,0 +1,64 @@
/***************************************************************************************
*
* 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.
*
****************************************************************************************/
#ifndef H264_UTIL_H
#define H264_UTIL_H
typedef struct
{
int i_ref_idc; // nal_priority_e
int i_type; // nal_unit_type_e
/* This data are raw payload */
int i_payload;
uint8 * p_payload;
} nal_t;
typedef struct
{
int i_width;
int i_height;
int i_nal_type;
int i_ref_idc;
int i_idr_pic_id;
int i_frame_num;
int i_poc;
int b_key;
int i_log2_max_frame_num;
int i_poc_type;
int i_log2_max_poc_lsb;
} h264_t;
#ifdef __cplusplus
extern "C" {
#endif
void h264_parser_init(h264_t * h);
void h264_parser_parse(h264_t * h, nal_t * nal, int * pb_nal_start);
#ifdef __cplusplus
}
#endif
#endif // H264_UTIL_H

72
MediaClient/rtp/h265.h Normal file
View File

@@ -0,0 +1,72 @@
/***************************************************************************************
*
* 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.
*
****************************************************************************************/
#ifndef H265_H
#define H265_H
/**
* NAL unit type codes
*/
enum HEVCNALUnitType
{
HEVC_NAL_TRAIL_N = 0,
HEVC_NAL_TRAIL_R = 1,
HEVC_NAL_TSA_N = 2,
HEVC_NAL_TSA_R = 3,
HEVC_NAL_STSA_N = 4,
HEVC_NAL_STSA_R = 5,
HEVC_NAL_RADL_N = 6,
HEVC_NAL_RADL_R = 7,
HEVC_NAL_RASL_N = 8,
HEVC_NAL_RASL_R = 9,
HEVC_NAL_BLA_W_LP = 16,
HEVC_NAL_BLA_W_RADL = 17,
HEVC_NAL_BLA_N_LP = 18,
HEVC_NAL_IDR_W_RADL = 19,
HEVC_NAL_IDR_N_LP = 20,
HEVC_NAL_CRA_NUT = 21,
HEVC_NAL_VPS = 32,
HEVC_NAL_SPS = 33,
HEVC_NAL_PPS = 34,
HEVC_NAL_AUD = 35,
HEVC_NAL_EOS_NUT = 36,
HEVC_NAL_EOB_NUT = 37,
HEVC_NAL_FD_NUT = 38,
HEVC_NAL_SEI_PREFIX = 39,
HEVC_NAL_SEI_SUFFIX = 40,
};
#define IS_IRAP_NAL(nal) (nal >= 16 && nal <= 23)
typedef struct
{
uint8 vps[256];
int vps_len;
uint8 sps[256];
int sps_len;
uint8 pps[256];
int pps_len;
} H265ParamSets;
#endif

View 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));
}

View File

@@ -0,0 +1,62 @@
/***************************************************************************************
*
* 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.
*
****************************************************************************************/
#ifndef H265_RTP_RX_H
#define H265_RTP_RX_H
#include "rtp_rx.h"
#include "h265.h"
typedef struct h265_rtp_rx_info
{
RTPRXI rtprxi; // rtp receive info
uint8 * p_buf_org; // Allocated buffer
uint8 * p_buf; // = p_buf_org + 32
uint32 buf_len; // Buffer length - 32
uint32 d_offset; // Data offset
VRTPRXCBF pkt_func; // callback function
void * user_data; // user data
BOOL rxf_don; // DON
H265ParamSets param_sets; // h265 parameter sets
} H265RXI;
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************/
BOOL h265_data_rx(H265RXI * p_rxi, uint8 * p_data, int len);
BOOL h265_rtp_rx(H265RXI * p_rxi, uint8 * p_data, int len);
BOOL h265_rxi_init(H265RXI * p_rxi, VRTPRXCBF cbf, void * p_userdata);
void h265_rxi_deinit(H265RXI * p_rxi);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,411 @@
/***************************************************************************************
*
* 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 "bs.h"
#include "util.h"
#include "h265.h"
#include "h265_util.h"
/**************************************************************************************/
int h265_extract_rbsp(const uint8 *src, int length, uint8 *dst)
{
int i, si, di;
for (i = 0; i + 1 < length; i += 2)
{
if (src[i])
{
continue;
}
if (i > 0 && src[i - 1] == 0)
{
i--;
}
if (i + 2 < length && src[i + 1] == 0 && src[i + 2] <= 3)
{
if (src[i + 2] != 3 && src[i + 2] != 0)
{
/* startcode, so we must be past the end */
length = i;
}
break;
}
}
if (i >= length - 1)
{
// no escaped 0
memcpy(dst, src, length);
return length;
}
memcpy(dst, src, i);
si = di = i;
while (si + 2 < length)
{
// remove escapes (very rare 1:2^22)
if (src[si + 2] > 3)
{
dst[di++] = src[si++];
dst[di++] = src[si++];
}
else if (src[si] == 0 && src[si + 1] == 0 && src[si + 2] != 0)
{
if (src[si + 2] == 3)
{
// escape
dst[di++] = 0;
dst[di++] = 0;
si += 3;
continue;
}
else // next start code
{
return si;
}
}
dst[di++] = src[si++];
}
while (si < length)
{
dst[di++] = src[si++];
}
return si;
}
void h265_parser_init(h265_t * h)
{
memset(h, 0, sizeof(h265_t));
}
int h265_parser_parse(h265_t * h, uint8 * p_data, int len)
{
uint32 i;
bs_t s;
uint8 bufs[512];
if (len > (int)sizeof(bufs))
{
return -1;
}
len = h265_extract_rbsp(p_data, len, bufs);
bs_init(&s, bufs, len);
bs_read(&s, 4); // sps_video_parameter_set_id u(4)
h->sps_max_sub_layers_minus1 = bs_read(&s, 3); // sps_max_sub_layers_minus1 u(3)
if (h->sps_max_sub_layers_minus1 > 6)
{
log_print(HT_LOG_ERR, "%s, sps_max_sub_layers_minus1[%d]>6!!!\r\n",
__FUNCTION__, h->sps_max_sub_layers_minus1);
return -1;
}
bs_read(&s, 1); // sps_temporal_id_nesting_flag u(1)
// profile_tier_level( maxNumSubLayersMinus1 )
{
bs_read(&s, 2); // general_profile_space u(2)
bs_read(&s, 1); // general_tier_flag u(1)
h->general_profile_idc = bs_read(&s, 5); // general_profile_idc u(5)
bs_read(&s, 32); // general_profile_compatibility_flag[ j ] u(5)
bs_read(&s, 1); // general_progressive_source_flag u(1)
bs_read(&s, 1); // general_interlaced_source_flag u(1)
bs_read(&s, 1); // general_non_packed_constraint_flag u(1)
bs_read(&s, 1); // general_frame_only_constraint_flag u(1)
bs_skip(&s, 44); // general_reserved_zero_44bits u(44)
h->general_level_idc = bs_read(&s, 8); // general_level_idc u(8)
uint8 sub_layer_profile_present_flag[6] = {0};
uint8 sub_layer_level_present_flag[6] = {0};
for (i = 0; i < h->sps_max_sub_layers_minus1; i++)
{
sub_layer_profile_present_flag[i]= bs_read(&s, 1);
sub_layer_level_present_flag[i]= bs_read(&s, 1);
}
if (h->sps_max_sub_layers_minus1 > 0)
{
for (i = h->sps_max_sub_layers_minus1; i < 8; i++)
{
bs_read(&s, 2);
}
}
for (i = 0; i < h->sps_max_sub_layers_minus1; i++)
{
if (sub_layer_profile_present_flag[i])
{
bs_read(&s, 2); // sub_layer_profile_space[i]
bs_read(&s, 1); // sub_layer_tier_flag[i]
bs_read(&s, 5); // sub_layer_profile_idc[i]
bs_read(&s, 32); // sub_layer_profile_compatibility_flag[i][32]
bs_read(&s, 1); // sub_layer_progressive_source_flag[i]
bs_read(&s, 1); // sub_layer_interlaced_source_flag[i]
bs_read(&s, 1); // sub_layer_non_packed_constraint_flag[i]
bs_read(&s, 1); // sub_layer_frame_only_constraint_flag[i]
bs_read(&s, 44); // sub_layer_reserved_zero_44bits[i]
}
if (sub_layer_level_present_flag[i])
{
bs_read(&s, 8); // sub_layer_level_idc[i]
}
}
}
h->sps_seq_parameter_set_id = bs_read_ue(&s); // sps_seq_parameter_set_id ue(v)
h->chroma_format_idc = bs_read_ue(&s); // chroma_format_idc ue(v)
if (h->chroma_format_idc > 3)
{
log_print(HT_LOG_ERR, "%s, chroma_format_idc[%d]!!!\r\n",
__FUNCTION__, h->chroma_format_idc);
return -1;
}
if (h->chroma_format_idc == 3)
{
h->separate_colour_plane_flag = bs_read(&s, 1); // separate_colour_plane_flag
}
h->pic_width_in_luma_samples = bs_read_ue(&s); // pic_width_in_luma_samples ue(v)
h->pic_height_in_luma_samples = bs_read_ue(&s); // pic_height_in_luma_samples ue(v)
h->conformance_window_flag = bs_read(&s, 1 ); // conformance_window_flag u(1)
if (h->conformance_window_flag)
{
h->conf_win_left_offset = bs_read_ue(&s); // conf_win_left_offset ue(v)
h->conf_win_right_offset = bs_read_ue(&s); // conf_win_right_offset ue(v)
h->conf_win_top_offset = bs_read_ue(&s); // conf_win_top_offset ue(v)
h->conf_win_bottom_offset = bs_read_ue(&s); // conf_win_bottom_offset ue(v)
}
h->bit_depth_luma_minus8 = bs_read_ue(&s); // bit_depth_luma_minus8 ue(v)
h->bit_depth_chroma_minus8 = bs_read_ue(&s); // bit_depth_chroma_minus8 ue(v)
return 0;
}
void hvcc_init(HEVCDecoderConfigurationRecord * hvcc)
{
memset(hvcc, 0, sizeof(HEVCDecoderConfigurationRecord));
hvcc->lengthSizeMinusOne = 3; // 4 bytes
/*
* The following fields have all their valid bits set by default,
* the ProfileTierLevel parsing code will unset them when needed.
*/
hvcc->general_profile_compatibility_flags = 0xffffffff;
hvcc->general_constraint_indicator_flags = 0xffffffffffff;
/*
* Initialize this field with an invalid value which can be used to detect
* whether we didn't see any VUI (in which case it should be reset to zero).
*/
hvcc->min_spatial_segmentation_idc = MAX_SPATIAL_SEGMENTATION + 1;
}
int hvcc_parse_vps(HEVCDecoderConfigurationRecord * hvcc, uint8 * p_data, int len)
{
uint32 vps_max_sub_layers_minus1;
uint8 bufs[512];
bs_t s;
if (len > (int)sizeof(bufs))
{
return -1;
}
len = h265_extract_rbsp(p_data, len, bufs);
bs_init(&s, bufs, len);
/*
* vps_video_parameter_set_id u(4)
* vps_reserved_three_2bits u(2)
* vps_max_layers_minus1 u(6)
*/
bs_skip(&s, 12);
vps_max_sub_layers_minus1 = bs_read(&s, 3);
/*
* numTemporalLayers greater than 1 indicates that the stream to which this
* configuration record applies is temporally scalable and the contained
* number of temporal layers (also referred to as temporal sub-layer or
* sub-layer in ISO/IEC 23008-2) is equal to numTemporalLayers. Value 1
* indicates that the stream is not temporally scalable. Value 0 indicates
* that it is unknown whether the stream is temporally scalable.
*/
hvcc->numTemporalLayers = MAX(hvcc->numTemporalLayers, vps_max_sub_layers_minus1 + 1);
/*
* vps_temporal_id_nesting_flag u(1)
* vps_reserved_0xffff_16bits u(16)
*/
bs_skip(&s, 17);
uint8 profile_space;
uint8 tier_flag;
uint8 profile_idc;
uint32 profile_compatibility_flags;
uint64 constraint_indicator_flags;
uint8 level_idc;
profile_space = bs_read(&s, 2);
tier_flag = bs_read(&s, 1);
profile_idc = bs_read(&s, 5);
profile_compatibility_flags = bs_read(&s, 32);
constraint_indicator_flags = (uint64)bs_read(&s, 16) << 32;
constraint_indicator_flags |= bs_read(&s, 32);
level_idc = bs_read(&s, 8);
hvcc->general_profile_space = profile_space;
/*
* The level indication general_level_idc must indicate a level of
* capability equal to or greater than the highest level indicated for the
* highest tier in all the parameter sets.
*/
if (hvcc->general_tier_flag < tier_flag)
hvcc->general_level_idc = level_idc;
else
hvcc->general_level_idc = MAX(hvcc->general_level_idc, level_idc);
/*
* The tier indication general_tier_flag must indicate a tier equal to or
* greater than the highest tier indicated in all the parameter sets.
*/
hvcc->general_tier_flag = MAX(hvcc->general_tier_flag, tier_flag);
/*
* The profile indication general_profile_idc must indicate a profile to
* which the stream associated with this configuration record conforms.
*
* If the sequence parameter sets are marked with different profiles, then
* the stream may need examination to determine which profile, if any, the
* entire stream conforms to. If the entire stream is not examined, or the
* examination reveals that there is no profile to which the entire stream
* conforms, then the entire stream must be split into two or more
* sub-streams with separate configuration records in which these rules can
* be met.
*
* Note: set the profile to the highest value for the sake of simplicity.
*/
hvcc->general_profile_idc = MAX(hvcc->general_profile_idc, profile_idc);
/*
* Each bit in general_profile_compatibility_flags may only be set if all
* the parameter sets set that bit.
*/
hvcc->general_profile_compatibility_flags &= profile_compatibility_flags;
/*
* Each bit in general_constraint_indicator_flags may only be set if all
* the parameter sets set that bit.
*/
hvcc->general_constraint_indicator_flags &= constraint_indicator_flags;
/* nothing useful for hvcC past this point */
return 0;
}
int hvcc_parse_pps(HEVCDecoderConfigurationRecord * hvcc, uint8 * p_data, int len)
{
uint8 tiles_enabled_flag, entropy_coding_sync_enabled_flag;
uint8 bufs[512];
bs_t s;
if (len > (int)sizeof(bufs))
{
return -1;
}
len = h265_extract_rbsp(p_data, len, bufs);
bs_init(&s, bufs, len);
bs_read_ue(&s); // pps_pic_parameter_set_id
bs_read_ue(&s); // pps_seq_parameter_set_id
/*
* dependent_slice_segments_enabled_flag u(1)
* output_flag_present_flag u(1)
* num_extra_slice_header_bits u(3)
* sign_data_hiding_enabled_flag u(1)
* cabac_init_present_flag u(1)
*/
bs_skip(&s, 7);
bs_read_ue(&s); // num_ref_idx_l0_default_active_minus1
bs_read_ue(&s); // num_ref_idx_l1_default_active_minus1
bs_read_se(&s); // init_qp_minus26
/*
* constrained_intra_pred_flag u(1)
* transform_skip_enabled_flag u(1)
*/
bs_skip(&s, 2);
if (bs_read(&s, 1)) // cu_qp_delta_enabled_flag
bs_read_ue(&s); // diff_cu_qp_delta_depth
bs_read_se(&s); // pps_cb_qp_offset
bs_read_se(&s); // pps_cr_qp_offset
/*
* pps_slice_chroma_qp_offsets_present_flag u(1)
* weighted_pred_flag u(1)
* weighted_bipred_flag u(1)
* transquant_bypass_enabled_flag u(1)
*/
bs_skip(&s, 4);
tiles_enabled_flag = bs_read(&s, 1);
entropy_coding_sync_enabled_flag = bs_read(&s, 1);
if (entropy_coding_sync_enabled_flag && tiles_enabled_flag)
hvcc->parallelismType = 0; // mixed-type parallel decoding
else if (entropy_coding_sync_enabled_flag)
hvcc->parallelismType = 3; // wavefront-based parallel decoding
else if (tiles_enabled_flag)
hvcc->parallelismType = 2; // tile-based parallel decoding
else
hvcc->parallelismType = 1; // slice-based parallel decoding
/* nothing useful for hvcC past this point */
return 0;
}

View File

@@ -0,0 +1,82 @@
/***************************************************************************************
*
* 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.
*
****************************************************************************************/
#ifndef H265_UTIL_H
#define H265_UTIL_H
#define MAX_SPATIAL_SEGMENTATION 4096 // max. value of u(12) field
typedef struct
{
int nal_len;
uint32 general_profile_idc;
uint32 general_level_idc;
uint32 separate_colour_plane_flag;
uint32 pic_width_in_luma_samples;
uint32 pic_height_in_luma_samples;
uint32 sps_max_sub_layers_minus1;
uint32 sps_seq_parameter_set_id;
uint32 chroma_format_idc;
uint32 conformance_window_flag;
uint32 conf_win_left_offset;
uint32 conf_win_right_offset;
uint32 conf_win_top_offset;
uint32 conf_win_bottom_offset;
uint32 bit_depth_luma_minus8;
uint32 bit_depth_chroma_minus8;
} h265_t;
typedef struct
{
uint8 general_profile_space;
uint8 general_tier_flag;
uint8 general_profile_idc;
uint32 general_profile_compatibility_flags;
uint64 general_constraint_indicator_flags;
uint8 general_level_idc;
uint16 min_spatial_segmentation_idc;
uint8 parallelismType;
uint8 chromaFormat;
uint8 bitDepthLumaMinus8;
uint8 bitDepthChromaMinus8;
uint16 avgFrameRate;
uint8 constantFrameRate;
uint8 numTemporalLayers;
uint8 temporalIdNested;
uint8 lengthSizeMinusOne;
} HEVCDecoderConfigurationRecord;
#ifdef __cplusplus
extern "C" {
#endif
void h265_parser_init(h265_t * h);
int h265_parser_parse(h265_t * h, uint8 * p_data, int len);
void hvcc_init(HEVCDecoderConfigurationRecord * hvcc);
int hvcc_parse_vps(HEVCDecoderConfigurationRecord * hvcc, uint8 * p_data, int len);
int hvcc_parse_pps(HEVCDecoderConfigurationRecord * hvcc, uint8 * p_data, int len);
#ifdef __cplusplus
}
#endif
#endif // H265_UTIL_H

108
MediaClient/rtp/mjpeg.h Normal file
View File

@@ -0,0 +1,108 @@
/***************************************************************************************
*
* 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.
*
****************************************************************************************/
#ifndef MJPEG_H
#define MJPEG_H
/* JPEG marker codes */
enum JpegMarker
{
/* start of frame */
MARKER_SOF0 = 0xc0, /* start-of-frame, baseline scan */
MARKER_SOF1 = 0xc1, /* extended sequential, huffman */
MARKER_SOF2 = 0xc2, /* progressive, huffman */
MARKER_SOF3 = 0xc3, /* lossless, huffman */
MARKER_SOF5 = 0xc5, /* differential sequential, huffman */
MARKER_SOF6 = 0xc6, /* differential progressive, huffman */
MARKER_SOF7 = 0xc7, /* differential lossless, huffman */
MARKER_JPG = 0xc8, /* reserved for JPEG extension */
MARKER_SOF9 = 0xc9, /* extended sequential, arithmetic */
MARKER_SOF10 = 0xca, /* progressive, arithmetic */
MARKER_SOF11 = 0xcb, /* lossless, arithmetic */
MARKER_SOF13 = 0xcd, /* differential sequential, arithmetic */
MARKER_SOF14 = 0xce, /* differential progressive, arithmetic */
MARKER_SOF15 = 0xcf, /* differential lossless, arithmetic */
MARKER_DHT = 0xc4, /* define huffman tables */
MARKER_DAC = 0xcc, /* define arithmetic-coding conditioning */
/* restart with modulo 8 count "m" */
MARKER_RST0 = 0xd0,
MARKER_RST1 = 0xd1,
MARKER_RST2 = 0xd2,
MARKER_RST3 = 0xd3,
MARKER_RST4 = 0xd4,
MARKER_RST5 = 0xd5,
MARKER_RST6 = 0xd6,
MARKER_RST7 = 0xd7,
MARKER_SOI = 0xd8, /* start of image */
MARKER_EOI = 0xd9, /* end of image */
MARKER_SOS = 0xda, /* start of scan */
MARKER_DQT = 0xdb, /* define quantization tables */
MARKER_DNL = 0xdc, /* define number of lines */
MARKER_DRI = 0xdd, /* restart interval */
MARKER_DHP = 0xde, /* define hierarchical progression */
MARKER_EXP = 0xdf, /* expand reference components */
MARKER_APP_FIRST= 0xe0,
MARKER_APP1 = 0xe1,
MARKER_APP2 = 0xe2,
MARKER_APP3 = 0xe3,
MARKER_APP4 = 0xe4,
MARKER_APP5 = 0xe5,
MARKER_APP6 = 0xe6,
MARKER_APP7 = 0xe7,
MARKER_APP8 = 0xe8,
MARKER_APP9 = 0xe9,
MARKER_APP10 = 0xea,
MARKER_APP11 = 0xeb,
MARKER_APP12 = 0xec,
MARKER_APP13 = 0xed,
MARKER_APP14 = 0xee,
MARKER_APP_LAST = 0xef,
MARKER_JPG0 = 0xf0,
MARKER_JPG1 = 0xf1,
MARKER_JPG2 = 0xf2,
MARKER_JPG3 = 0xf3,
MARKER_JPG4 = 0xf4,
MARKER_JPG5 = 0xf5,
MARKER_JPG6 = 0xf6,
MARKER_SOF48 = 0xf7,
MARKER_LSE = 0xf8,
MARKER_JPG9 = 0xf9,
MARKER_JPG10 = 0xfa,
MARKER_JPG11 = 0xfb,
MARKER_JPG12 = 0xfc,
MARKER_JPG13 = 0xfd,
MARKER_COMMENT = 0xfe,
MARKER_TEM = 0x01, /* temporary private use for arithmetic coding */
/* 0x02 -> 0xbf reserved */
};
#endif /* MJPEG_H */

View File

@@ -0,0 +1,397 @@
/***************************************************************************************
*
* 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 "mjpeg.h"
#include "mjpeg_rtp_rx.h"
#include "mjpeg_tables.h"
static void mjpeg_create_huffman_header
(
uint8*& p,
uint8 const* codelens,
int ncodes,
uint8 const* symbols,
int nsymbols,
int tableNo, int tableClass
)
{
*p++ = 0xff; *p++ = MARKER_DHT;
*p++ = 0; /* length msb */
*p++ = 3 + ncodes + nsymbols; /* length lsb */
*p++ = (tableClass << 4) | tableNo;
memcpy(p, codelens, ncodes);
p += ncodes;
memcpy(p, symbols, nsymbols);
p += nsymbols;
}
uint32 mjpeg_compute_header_size(uint32 qtlen, uint32 dri)
{
uint32 qtlen_half = qtlen/2; // in case qtlen is odd; shouldn't happen
qtlen = qtlen_half*2;
uint32 numQtables = qtlen > 64 ? 2 : 1;
return 485 + numQtables*5 + qtlen + (dri > 0 ? 6 : 0);
}
int mjpeg_create_header
(
uint8* buf, uint32 type,
uint32 w, uint32 h,
uint8 const* qtables, uint32 qtlen,
uint32 dri
)
{
uint8 *ptr = buf;
uint32 numQtables = qtlen > 64 ? 2 : 1;
// MARKER_SOI:
*ptr++ = 0xFF; *ptr++ = MARKER_SOI;
// MARKER_APP_FIRST:
*ptr++ = 0xFF; *ptr++ = MARKER_APP_FIRST;
*ptr++ = 0x00; *ptr++ = 0x10; // size of chunk
*ptr++ = 'J'; *ptr++ = 'F'; *ptr++ = 'I'; *ptr++ = 'F'; *ptr++ = 0x00;
*ptr++ = 0x01; *ptr++ = 0x01; // JFIF format version (1.1)
*ptr++ = 0x00; // no units
*ptr++ = 0x00; *ptr++ = 0x01; // Horizontal pixel aspect ratio
*ptr++ = 0x00; *ptr++ = 0x01; // Vertical pixel aspect ratio
*ptr++ = 0x00; *ptr++ = 0x00; // no thumbnail
// MARKER_DRI:
if (dri > 0)
{
*ptr++ = 0xFF; *ptr++ = MARKER_DRI;
*ptr++ = 0x00; *ptr++ = 0x04; // size of chunk
*ptr++ = (uint8)(dri >> 8); *ptr++ = (uint8)(dri); // restart interval
}
// MARKER_DQT (luma):
uint32 tableSize = numQtables == 1 ? qtlen : qtlen/2;
*ptr++ = 0xFF; *ptr++ = MARKER_DQT;
*ptr++ = 0x00; *ptr++ = tableSize + 3; // size of chunk
*ptr++ = 0x00; // precision(0), table id(0)
memcpy(ptr, qtables, tableSize);
qtables += tableSize;
ptr += tableSize;
if (numQtables > 1)
{
tableSize = qtlen - qtlen/2;
// MARKER_DQT (chroma):
*ptr++ = 0xFF; *ptr++ = MARKER_DQT;
*ptr++ = 0x00; *ptr++ = tableSize + 3; // size of chunk
*ptr++ = 0x01; // precision(0), table id(1)
memcpy(ptr, qtables, tableSize);
qtables += tableSize;
ptr += tableSize;
}
// MARKER_SOF0:
*ptr++ = 0xFF; *ptr++ = MARKER_SOF0;
*ptr++ = 0x00; *ptr++ = 0x11; // size of chunk
*ptr++ = 0x08; // sample precision
*ptr++ = (uint8)(h >> 8);
*ptr++ = (uint8)(h); // number of lines (must be a multiple of 8)
*ptr++ = (uint8)(w >> 8);
*ptr++ = (uint8)(w); // number of columns (must be a multiple of 8)
*ptr++ = 0x03; // number of components
*ptr++ = 0x01; // id of component
*ptr++ = type ? 0x22 : 0x21; // sampling ratio (h,v)
*ptr++ = 0x00; // quant table id
*ptr++ = 0x02; // id of component
*ptr++ = 0x11; // sampling ratio (h,v)
*ptr++ = numQtables == 1 ? 0x00 : 0x01; // quant table id
*ptr++ = 0x03; // id of component
*ptr++ = 0x11; // sampling ratio (h,v)
*ptr++ = numQtables == 1 ? 0x00 : 0x01; // quant table id
mjpeg_create_huffman_header(ptr, lum_dc_codelens, sizeof lum_dc_codelens,
lum_dc_symbols, sizeof lum_dc_symbols, 0, 0);
mjpeg_create_huffman_header(ptr, lum_ac_codelens, sizeof lum_ac_codelens,
lum_ac_symbols, sizeof lum_ac_symbols, 0, 1);
mjpeg_create_huffman_header(ptr, chm_dc_codelens, sizeof chm_dc_codelens,
chm_dc_symbols, sizeof chm_dc_symbols, 1, 0);
mjpeg_create_huffman_header(ptr, chm_ac_codelens, sizeof chm_ac_codelens,
chm_ac_symbols, sizeof chm_ac_symbols, 1, 1);
// MARKER_SOS:
*ptr++ = 0xFF; *ptr++ = MARKER_SOS;
*ptr++ = 0x00; *ptr++ = 0x0C; // size of chunk
*ptr++ = 0x03; // number of components
*ptr++ = 0x01; // id of component
*ptr++ = 0x00; // huffman table id (DC, AC)
*ptr++ = 0x02; // id of component
*ptr++ = 0x11; // huffman table id (DC, AC)
*ptr++ = 0x03; // id of component
*ptr++ = 0x11; // huffman table id (DC, AC)
*ptr++ = 0x00; // start of spectral
*ptr++ = 0x3F; // end of spectral
*ptr++ = 0x00; // successive approximation bit position (high, low)
return (int)(ptr - buf);
}
// The default 'luma' and 'chroma' quantizer tables, in zigzag order:
static uint8 const defaultQuantizers[128] =
{
// luma table:
16, 11, 12, 14, 12, 10, 16, 14,
13, 14, 18, 17, 16, 19, 24, 40,
26, 24, 22, 22, 24, 49, 35, 37,
29, 40, 58, 51, 61, 60, 57, 51,
56, 55, 64, 72, 92, 78, 64, 68,
87, 69, 55, 56, 80, 109, 81, 87,
95, 98, 103, 104, 103, 62, 77, 113,
121, 112, 100, 120, 92, 101, 103, 99,
// chroma table:
17, 18, 18, 24, 21, 24, 47, 26,
26, 47, 99, 66, 56, 66, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99
};
void mjpeg_make_default_qtables(uint8* resultTables, uint32 Q)
{
int factor = Q;
int q;
if (Q < 1) factor = 1;
else if (Q > 99) factor = 99;
if (Q < 50)
{
q = 5000 / factor;
}
else
{
q = 200 - factor*2;
}
for (int i = 0; i < 128; ++i)
{
int newVal = (defaultQuantizers[i]*q + 50)/100;
if (newVal < 1) newVal = 1;
else if (newVal > 255) newVal = 255;
resultTables[i] = newVal;
}
}
BOOL mjpeg_data_rx(MJPEGRXI * p_rxi, uint8 * p_data, int len)
{
uint8* headerStart = p_data;
uint32 packetSize = len;
uint32 resultSpecialHeaderSize = 0;
uint8* qtables = NULL;
uint32 qtlen = 0;
uint32 dri = 0;
// There's at least 8-byte video-specific header
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type-specific | Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Q | Width | Height |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
resultSpecialHeaderSize = 8;
uint32 Offset = (uint32)((uint32)headerStart[1] << 16 | (uint32)headerStart[2] << 8 | (uint32)headerStart[3]);
uint32 Type = (uint32)headerStart[4];
uint32 type = Type & 1;
uint32 Q = (uint32)headerStart[5];
uint32 width = (uint32)headerStart[6] * 8;
uint32 height = (uint32)headerStart[7] * 8;
if (width == 0)
{
width = p_rxi->width ? p_rxi->width : 256*8;
}
if (height == 0)
{
height = p_rxi->height ? p_rxi->height : 256*8;
}
if (Type > 63)
{
// Restart Marker header present
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Restart Interval |F|L| Restart Count |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
if (packetSize < resultSpecialHeaderSize + 4)
{
return FALSE;
}
uint32 RestartInterval = (uint32)((uint16)headerStart[resultSpecialHeaderSize] << 8 | (uint16)headerStart[resultSpecialHeaderSize + 1]);
dri = RestartInterval;
resultSpecialHeaderSize += 4;
}
if (Offset == 0)
{
if (Q > 127)
{
// Quantization Table header present
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| MBZ | Precision | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Quantization Table Data |
| ... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
if (packetSize < resultSpecialHeaderSize + 4)
{
return FALSE;
}
uint32 MBZ = (uint32)headerStart[resultSpecialHeaderSize];
if (MBZ == 0)
{
// uint32 Precision = (uint32)headerStart[resultSpecialHeaderSize + 1];
uint32 Length = (uint32)((uint16)headerStart[resultSpecialHeaderSize + 2] << 8 | (uint16)headerStart[resultSpecialHeaderSize + 3]);
//ASSERT(Length == 128);
resultSpecialHeaderSize += 4;
if (packetSize < resultSpecialHeaderSize + Length)
{
return FALSE;
}
qtlen = Length;
qtables = &headerStart[resultSpecialHeaderSize];
resultSpecialHeaderSize += Length;
}
}
}
// If this is the first (or only) fragment of a JPEG frame
if (Offset == 0)
{
uint8 newQtables[128];
if (qtlen == 0)
{
// A quantization table was not present in the RTP JPEG header,
// so use the default tables, scaled according to the "Q" factor:
mjpeg_make_default_qtables(newQtables, Q);
qtables = newQtables;
qtlen = sizeof newQtables;
}
p_rxi->d_offset = mjpeg_create_header(p_rxi->p_buf, type, width, height, qtables, qtlen, dri);
}
if ((p_rxi->d_offset + packetSize - resultSpecialHeaderSize) >= p_rxi->buf_len)
{
log_print(HT_LOG_ERR, "%s, fragment packet too big %d!!!", __FUNCTION__, p_rxi->d_offset + packetSize - resultSpecialHeaderSize);
return FALSE;
}
memcpy(p_rxi->p_buf + p_rxi->d_offset, headerStart + resultSpecialHeaderSize, packetSize - resultSpecialHeaderSize);
p_rxi->d_offset += packetSize - resultSpecialHeaderSize;
// The RTP "M" (marker) bit indicates the last fragment of a frame:
if (p_rxi->rtprxi.rxf_marker)
{
if (p_rxi->d_offset >= 2 && !(p_rxi->p_buf[p_rxi->d_offset-2] == 0xFF && p_rxi->p_buf[p_rxi->d_offset-1] == MARKER_EOI))
{
p_rxi->p_buf[p_rxi->d_offset++] = 0xFF;
p_rxi->p_buf[p_rxi->d_offset++] = MARKER_EOI;
}
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 mjpeg_rtp_rx(MJPEGRXI * 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 mjpeg_data_rx(p_rxi, p_rxi->rtprxi.p_data, p_rxi->rtprxi.len);
}
BOOL mjpeg_rxi_init(MJPEGRXI * p_rxi, VRTPRXCBF cbf, void * p_userdata)
{
memset(p_rxi, 0, sizeof(MJPEGRXI));
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 FALSE;
}
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 TRUE;
}
void mjpeg_rxi_deinit(MJPEGRXI * p_rxi)
{
if (p_rxi->p_buf_org)
{
free(p_rxi->p_buf_org);
}
memset(p_rxi, 0, sizeof(MJPEGRXI));
}

View File

@@ -0,0 +1,62 @@
/***************************************************************************************
*
* 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.
*
****************************************************************************************/
#ifndef MJPEG_RTP_RX_H
#define MJPEG_RTP_RX_H
#include "rtp_rx.h"
typedef struct mjpeg_rtp_rx_info
{
RTPRXI rtprxi;
uint8 * p_buf_org; // Allocated buffer
uint8 * p_buf; // = p_buf_org + 32
uint32 buf_len; // Buffer length -32
uint32 d_offset; // Data offset
VRTPRXCBF pkt_func; // callback function
void * user_data; // user data
int width; // video width
int height; // video height
} MJPEGRXI;
/***************************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
BOOL mjpeg_data_rx(MJPEGRXI * p_rxi, uint8 * p_data, int len);
BOOL mjpeg_rtp_rx(MJPEGRXI * p_rxi, uint8 * p_data, int len);
BOOL mjpeg_rxi_init(MJPEGRXI * p_rxi, VRTPRXCBF cbf, void * p_userdata);
void mjpeg_rxi_deinit(MJPEGRXI * p_rxi);
#ifdef __cplusplus
}
#endif
#endif // MJPEG_RTP_RX_H

View File

@@ -0,0 +1,97 @@
/***************************************************************************************
*
* 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 "mjpeg_tables.h"
uint8 const lum_dc_codelens[16] = {
0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
};
uint8 const lum_dc_symbols[12] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
};
uint8 const lum_ac_codelens[16] = {
0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d,
};
uint8 const lum_ac_symbols[] = {
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa,
};
uint8 const chm_dc_codelens[16] = {
0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
};
uint8 const chm_dc_symbols[12] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
};
uint8 const chm_ac_codelens[16] = {
0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77,
};
uint8 const chm_ac_symbols[] = {
0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa,
};

View File

@@ -0,0 +1,42 @@
/***************************************************************************************
*
* 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.
*
****************************************************************************************/
#ifndef MJPEG_TABLES_H
#define MJPEG_TABLES_H
#ifdef __cplusplus
extern "C" {
#endif
extern uint8 const lum_dc_codelens[16];
extern uint8 const lum_dc_symbols[12];
extern uint8 const lum_ac_codelens[16];
extern uint8 const lum_ac_symbols[162];
extern uint8 const chm_dc_codelens[16];
extern uint8 const chm_dc_symbols[12];
extern uint8 const chm_ac_codelens[16];
extern uint8 const chm_ac_symbols[162];
#ifdef __cplusplus
}
#endif
#endif // MJPEG_TABLES_H

126
MediaClient/rtp/mpeg4.cpp Normal file
View File

@@ -0,0 +1,126 @@
/***************************************************************************************
*
* 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 "mpeg4.h"
static BOOL mpeg4_get_nibble(char const*& configStr, uint8& resultNibble)
{
char c = configStr[0];
if (c == '\0')
{
return FALSE; // we've reached the end
}
if (c >= '0' && c <= '9')
{
resultNibble = c - '0';
}
else if (c >= 'A' && c <= 'F')
{
resultNibble = 10 + c - 'A';
}
else if (c >= 'a' && c <= 'f')
{
resultNibble = 10 + c - 'a';
}
else
{
return FALSE;
}
++configStr; // move to the next nibble
return TRUE;
}
static BOOL mpeg4_get_byte(char const*& configStr, uint8& resultByte)
{
resultByte = 0; // by default, in case parsing fails
uint8 firstNibble;
if (!mpeg4_get_nibble(configStr, firstNibble))
{
return FALSE;
}
resultByte = firstNibble << 4;
uint8 secondNibble = 0;
if (!mpeg4_get_nibble(configStr, secondNibble) && configStr[0] != '\0')
{
// There's a second nibble, but it's malformed
return FALSE;
}
resultByte |= secondNibble;
return TRUE;
}
uint8 * mpeg4_parse_config(char const* configStr, uint32& configSize)
{
uint8 * config = NULL;
do
{
if (configStr == NULL)
{
break;
}
configSize = ((int)strlen(configStr)+1)/2;
config = (uint8 *) malloc(configSize);
if (config == NULL)
{
break;
}
uint32 i;
for (i = 0; i < configSize; ++i)
{
if (!mpeg4_get_byte(configStr, config[i]))
{
break;
}
}
if (i != configSize)
{
break; // part of the string was bad
}
return config;
} while (0);
configSize = 0;
if (config)
{
free(config);
}
return NULL;
}

37
MediaClient/rtp/mpeg4.h Normal file
View File

@@ -0,0 +1,37 @@
/***************************************************************************************
*
* 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.
*
****************************************************************************************/
#ifndef MPEG4_H
#define MPEG4_H
#ifdef __cplusplus
extern "C" {
#endif
uint8 * mpeg4_parse_config(char const* configStr, uint32& configSize);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,124 @@
/***************************************************************************************
*
* 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 "mpeg4_rtp_rx.h"
BOOL mpeg4_data_rx(MPEG4RXI * p_rxi, uint8 * p_data, int len)
{
BOOL begin_packet = FALSE;
// The packet begins a frame iff its data begins with a system code
// (i.e., 0x000001??)
begin_packet = (len >= 4 && p_data[0] == 0 && p_data[1] == 0 && p_data[2] == 1);
if (begin_packet)
{
p_rxi->d_offset = 0;
}
if (p_rxi->rtprxi.rxf_loss)
{
// Packet loss, discard the previously cached packets
p_rxi->d_offset = 0;
// Packet loss, until the next start packet
if (!begin_packet)
{
return FALSE;
}
else
{
p_rxi->rtprxi.rxf_loss = 0;
}
}
if ((p_rxi->d_offset + len + p_rxi->hdr_len) >= p_rxi->buf_len)
{
log_print(HT_LOG_ERR, "%s, fragment packet too big %d!!!",
__FUNCTION__, p_rxi->d_offset + len + p_rxi->hdr_len);
return FALSE;
}
memcpy(p_rxi->p_buf + p_rxi->d_offset + p_rxi->hdr_len, p_data, len);
p_rxi->d_offset += len;
if (p_rxi->rtprxi.rxf_marker)
{
if (p_rxi->pkt_func)
{
p_rxi->pkt_func(p_rxi->p_buf, p_rxi->d_offset + p_rxi->hdr_len, p_rxi->rtprxi.ts, p_rxi->rtprxi.seq, p_rxi->user_data);
}
p_rxi->d_offset = 0;
}
return TRUE;
}
BOOL mpeg4_rtp_rx(MPEG4RXI * 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 mpeg4_data_rx(p_rxi, p_rxi->rtprxi.p_data, p_rxi->rtprxi.len);
}
BOOL mpeg4_rxi_init(MPEG4RXI * p_rxi, VRTPRXCBF cbf, void * p_userdata)
{
memset(p_rxi, 0, sizeof(MPEG4RXI));
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 FALSE;
}
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 TRUE;
}
void mpeg4_rxi_deinit(MPEG4RXI * p_rxi)
{
if (p_rxi->p_buf_org)
{
free(p_rxi->p_buf_org);
}
memset(p_rxi, 0, sizeof(MPEG4RXI));
}

View File

@@ -0,0 +1,58 @@
/***************************************************************************************
*
* 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.
*
****************************************************************************************/
#ifndef MPEG4_RTX_RX_H
#define MPEG4_RTX_RX_H
#include "rtp_rx.h"
typedef struct mpeg4_rtp_rx_info
{
RTPRXI rtprxi;
uint8 * p_buf_org; // Allocated buffer
uint8 * p_buf; // = p_buf_org + 32
uint32 buf_len; // Buffer length -32
uint32 d_offset; // Data offset
VRTPRXCBF pkt_func; // callback function
void * user_data; // user data
uint32 hdr_len; // header length
} MPEG4RXI;
#ifdef __cplusplus
extern "C" {
#endif
BOOL mpeg4_data_rx(MPEG4RXI * p_rxi, uint8 * p_data, int len);
BOOL mpeg4_rtp_rx(MPEG4RXI * p_rxi, uint8 * p_data, int len);
BOOL mpeg4_rxi_init(MPEG4RXI * p_rxi, VRTPRXCBF cbf, void * p_userdata);
void mpeg4_rxi_deinit(MPEG4RXI * p_rxi);
#ifdef __cplusplus
}
#endif
#endif // MPEG4_RTX_RX_H

View File

@@ -0,0 +1,113 @@
/***************************************************************************************
*
* 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 "pcm_rtp_rx.h"
BOOL pcm_data_rx(PCMRXI * p_rxi, uint8 * p_data, int len)
{
if (p_rxi->rtprxi.rxf_loss)
{
// Submit cached data
if (p_rxi->pkt_func && p_rxi->d_offset > 0)
{
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;
p_rxi->rtprxi.rxf_loss = 0;
}
if ((p_rxi->d_offset + len) >= p_rxi->buf_len)
{
// Submit cached data
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;
}
memcpy(p_rxi->p_buf + p_rxi->d_offset, p_data, len);
p_rxi->d_offset += len;
if (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 pcm_rtp_rx(PCMRXI * 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 pcm_data_rx(p_rxi, p_rxi->rtprxi.p_data, p_rxi->rtprxi.len);
}
BOOL pcm_rxi_init(PCMRXI * p_rxi, VRTPRXCBF cbf, void * p_userdata)
{
memset(p_rxi, 0, sizeof(PCMRXI));
p_rxi->buf_len = RTP_MAX_AUDIO_BUFF;
p_rxi->p_buf_org = (uint8 *)malloc(p_rxi->buf_len);
if (p_rxi->p_buf_org == NULL)
{
return FALSE;
}
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 TRUE;
}
void pcm_rxi_deinit(PCMRXI * p_rxi)
{
if (p_rxi->p_buf_org)
{
free(p_rxi->p_buf_org);
}
memset(p_rxi, 0, sizeof(PCMRXI));
}

View File

@@ -0,0 +1,59 @@
/***************************************************************************************
*
* 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.
*
****************************************************************************************/
#ifndef PCM_RTP_RX_H
#define PCM_RTP_RX_H
#include "rtp_rx.h"
typedef struct pcm_rtp_rx_info
{
RTPRXI rtprxi;
uint8 * p_buf_org; // Allocated buffer
uint8 * p_buf; // = p_buf_org + 32
uint32 buf_len; // Buffer length -32
uint32 d_offset; // Data offset
VRTPRXCBF pkt_func; // callback function
void * user_data; // user data
} PCMRXI;
/***************************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
BOOL pcm_data_rx(PCMRXI * p_rxi, uint8 * p_data, int len);
BOOL pcm_rtp_rx(PCMRXI * p_rxi, uint8 * p_data, int len);
BOOL pcm_rxi_init(PCMRXI * p_rxi, VRTPRXCBF cbf, void * p_userdata);
void pcm_rxi_deinit(PCMRXI * p_rxi);
#ifdef __cplusplus
}
#endif
#endif // PCM_RTP_RX_H

60
MediaClient/rtp/rtp.cpp Normal file
View File

@@ -0,0 +1,60 @@
/***************************************************************************************
*
* 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"
uint16 rtp_read_uint16(uint8 *input)
{
return (uint16)((input[0] << 8) | input[1]);
}
uint32 rtp_read_uint32(uint8 *input)
{
return (uint32)((input[0] << 24) | (input[1] << 16) | (input[2] << 8) | input[3]);
}
uint64 rtp_read_uint64(uint8 *input)
{
uint32 low = rtp_read_uint32(input);
uint32 high = rtp_read_uint32(input+4);
return (uint64)(((uint64)low) << 32 | high);
}
int rtp_write_uint16(uint8 *output, uint16 nVal)
{
output[1] = nVal & 0xff;
output[0] = nVal >> 8;
return 2;
}
int rtp_write_uint32(uint8 *output, uint32 nVal)
{
output[3] = nVal & 0xff;
output[2] = nVal >> 8;
output[1] = nVal >> 16;
output[0] = nVal >> 24;
return 4;
}

83
MediaClient/rtp/rtp.h Normal file
View File

@@ -0,0 +1,83 @@
/***************************************************************************************
*
* 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.
*
****************************************************************************************/
#ifndef __H_RTP_H__
#define __H_RTP_H__
#define H26X_RTP_MAX_LEN (1450 - 4 - 12 - 2 - 16) // TCP RTP FU REPLAYHDR
#define JPEG_RTP_MAX_LEN (1450 - 4 - 12 - 16)
#define RTP_MAX_LEN (1450 - 4 - 12 - 16)
/*
* Current protocol version.
*/
#define RTP_VERSION 2
#define RTP_SEQ_MOD (1<<16)
#define RTP_MAX_SDES 255 /* maximum text length for SDES */
typedef enum {
RTCP_FIR = 192,
RTCP_NACK, // 193
RTCP_SMPTETC, // 194
RTCP_IJ, // 195
RTCP_SR = 200,
RTCP_RR, // 201
RTCP_SDES, // 202
RTCP_BYE, // 203
RTCP_APP, // 204
RTCP_RTPFB, // 205
RTCP_PSFB, // 206
RTCP_XR, // 207
RTCP_AVB, // 208
RTCP_RSI, // 209
RTCP_TOKEN, // 210
} rtcp_type_t;
#define RTP_PT_IS_RTCP(x) (((x) >= RTCP_FIR && (x) <= RTCP_IJ) || \
((x) >= RTCP_SR && (x) <= RTCP_TOKEN))
typedef struct
{
uint32 magic : 8;
uint32 channel : 8;
uint32 rtp_len : 16;
} RILF;
uint16 rtp_read_uint16(uint8 *input);
uint32 rtp_read_uint32(uint8 *input);
uint64 rtp_read_uint64(uint8 *input);
int rtp_write_uint16(uint8 *output, uint16 nVal);
int rtp_write_uint32(uint8 *output, uint32 nVal);
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif // __H_RTP_H__

123
MediaClient/rtp/rtp_rx.cpp Normal file
View File

@@ -0,0 +1,123 @@
/***************************************************************************************
*
* 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_rx.h"
#include "rtp.h"
BOOL rtp_data_rx(RTPRXI * p_rxi, uint8 * p_data, int len)
{
uint8 * p_rtp = p_data;
uint32 rtp_len = len;
// Check for the 12-byte RTP header:
if (rtp_len < 12)
{
return FALSE;
}
uint32 rtpHdr = rtp_read_uint32(p_rtp); p_rtp += 4; rtp_len -= 4;
uint8 rtpPT = ((rtpHdr & 0x007f0000) >> 16);
BOOL rtpMarkerBit = (rtpHdr & 0x00800000) != 0;
uint16 rtpSeq = rtpHdr & 0xFFFF;
uint32 rtpTimestamp = rtp_read_uint32(p_rtp); p_rtp += 4; rtp_len -= 4;
uint32 rtpSSRC = rtp_read_uint32(p_rtp); p_rtp += 4; rtp_len -= 4;
// Check the RTP version number (it should be 2)
if ((rtpHdr & 0xC0000000) != 0x80000000)
{
return FALSE;
}
// Skip over any CSRC identifiers in the header
uint32 cc = (rtpHdr >> 24) & 0x0F;
if (rtp_len < cc * 4)
{
return FALSE;
}
p_rtp += cc * 4; rtp_len -= cc * 4;
// Check for (& ignore) any RTP header extension
if (rtpHdr & 0x10000000)
{
if (rtp_len < 4)
{
return FALSE;
}
uint32 extHdr = rtp_read_uint32(p_rtp); p_rtp += 4; rtp_len -= 4;
uint32 remExtSize = 4 * (extHdr & 0xFFFF);
if (rtp_len < remExtSize)
{
return FALSE;
}
p_rtp += remExtSize; rtp_len -= remExtSize;
}
// Discard any padding bytes:
if (rtpHdr & 0x20000000)
{
if (rtp_len == 0)
{
return FALSE;
}
uint32 numPaddingBytes = (uint32)p_rtp[rtp_len-1];
if (rtp_len < numPaddingBytes)
{
return FALSE;
}
rtp_len -= numPaddingBytes;
}
if (0 == p_rxi->rtp_pt)
{
p_rxi->rtp_pt = rtpPT;
}
else if (rtpPT != p_rxi->rtp_pt)
{
return FALSE;
}
if (p_rxi->ssrc && p_rxi->ssrc != rtpSSRC)
{
log_print(HT_LOG_WARN, "%s, prev ssrc[%u], cur ssrc[%u]!!!\r\n", __FUNCTION__, p_rxi->ssrc, rtpSSRC);
}
p_rxi->ssrc = rtpSSRC;
if (p_rxi->seq && p_rxi->seq != (uint16)(rtpSeq - 1))
{
p_rxi->rxf_loss = 1;
log_print(HT_LOG_WARN, "%s, prev seq[%u], cur seq[%u]!!!\r\n", __FUNCTION__, p_rxi->seq, rtpSeq);
}
p_rxi->seq = rtpSeq;
p_rxi->rxf_marker = rtpMarkerBit;
p_rxi->ts = rtpTimestamp;
p_rxi->p_data = p_rtp;
p_rxi->len = rtp_len;
return TRUE;
}

60
MediaClient/rtp/rtp_rx.h Normal file
View File

@@ -0,0 +1,60 @@
/***************************************************************************************
*
* 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.
*
****************************************************************************************/
#ifndef RTP_RX_H
#define RTP_RX_H
#define RTP_MAX_VIDEO_BUFF (2*1024*1024)
#define RTP_MAX_AUDIO_BUFF (8*1024)
typedef int (*VRTPRXCBF)(uint8 * p_data, int len, uint32 ts, uint32 seq, void * p_userdata);
typedef struct
{
uint32 rxf_marker : 1; // Marker bit
uint32 rxf_loss : 1; // The loss of sequence numbers has occurred in the middle
uint32 rtp_pt : 8; // rtp payload type
uint32 res1 : 6;
uint32 seq : 16; // sequence number
uint32 ssrc; // Synchronization source
uint32 ts; // Timestamp
uint8 * p_data;
int len;
} RTPRXI;
#ifdef __cplusplus
extern "C" {
#endif
BOOL rtp_data_rx(RTPRXI * p_rxi, uint8 * p_data, int len);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,627 @@
/***************************************************************************************
*
* 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 "ts_parser.h"
#include "bs.h"
BOOL ts_parser_add_item_to_list(TSList * list, void * data)
{
TSListItem * item = (TSListItem *)malloc(sizeof(TSListItem));
if (NULL == item)
{
return FALSE;
}
item->mData = data;
item->mNext = NULL;
if (list->mTail != NULL)
{
list->mTail->mNext = item;
list->mTail = item;
}
else
{
list->mHead = list->mTail = item;
}
return TRUE;
}
BOOL ts_parser_add_program(TSParser * parser, uint32 program_map_pid)
{
TSProgram * program = (TSProgram *)malloc(sizeof(TSProgram));
if (NULL == program)
{
return FALSE;
}
memset(program, 0, sizeof(TSProgram));
program->mProgramMapPID = program_map_pid;
return ts_parser_add_item_to_list(&parser->mPrograms, program);
}
BOOL ts_parser_add_stream(TSProgram * program, uint32 elementaryPID, uint32 streamType)
{
TSStream * stream = (TSStream *)malloc(sizeof(TSStream));
if (NULL == stream)
{
return FALSE;
}
memset(stream, 0, sizeof(TSStream));
stream->mProgram = program;
stream->mElementaryPID = elementaryPID;
stream->mStreamType = streamType;
// todo : The maximum receive buffer should be allocated based on streamType
log_print(HT_LOG_INFO, "%s, add stream, pid: %d, stream type: %d (%X)\r\n",
__FUNCTION__, elementaryPID, streamType, streamType);
return ts_parser_add_item_to_list(&program->mStreams, stream);
}
TSStream * ts_parser_get_stream_by_pid(TSProgram * program, uint32 pid)
{
TSListItem *item;
TSStream *stream;
for (item = program->mStreams.mHead; item != NULL; item = item->mNext)
{
stream = (TSStream *)item->mData;
if (stream != NULL && stream->mElementaryPID == pid)
{
return stream;
}
}
return NULL;
}
int64 ts_parser_parse_timestamp(bs_t * bs)
{
int64 result = ((uint64)bs_read(bs, 3)) << 30;
bs_skip(bs, 1);
result |= ((uint64)bs_read(bs, 15)) << 15;
bs_skip(bs, 1);
result |= bs_read(bs, 15);
return result;
}
int64 ts_parser_pts_to_timestamp(TSStream * stream, uint64 PTS)
{
if (!stream->mProgram->mFirstPTSValid)
{
stream->mProgram->mFirstPTSValid = 1;
stream->mProgram->mFirstPTS = PTS;
PTS = 0;
}
else if (PTS < stream->mProgram->mFirstPTS)
{
PTS = 0;
}
else
{
PTS -= stream->mProgram->mFirstPTS;
}
return (PTS * 100) / 9;
}
void ts_parser_on_payload_data(TSParser * parser, TSStream * stream, uint32 PTS_DTS_flag, uint64 PTS, uint64 DTS, uint8 *data, uint32 size)
{
// int64 timeUs = ts_parser_pts_to_timestamp(stream, PTS);
sys_os_mutex_enter(parser->mMutex);
if (parser->mCallback)
{
parser->mCallback(data, size, stream->mStreamType, PTS, parser->mUserdata);
}
sys_os_mutex_leave(parser->mMutex);
}
void ts_parser_parse_pes(TSParser * parser, TSStream * stream, bs_t * bs)
{
bs_read(bs, 24); // packet_startcode_prefix
uint32 stream_id = bs_read(bs, 8);
uint32 PES_packet_length = bs_read(bs, 16);
if (stream_id != 0xbc // program_stream_map
&& stream_id != 0xbe // padding_stream
&& stream_id != 0xbf // private_stream_2
&& stream_id != 0xf0 // ECM
&& stream_id != 0xf1 // EMM
&& stream_id != 0xff // program_stream_directory
&& stream_id != 0xf2 // DSMCC
&& stream_id != 0xf8) // H.222.1 type E
{
uint32 PTS_DTS_flags;
uint32 ESCR_flag;
uint32 ES_rate_flag;
uint32 PES_header_data_length;
uint32 optional_bytes_remaining;
uint64 PTS = 0, DTS = 0;
bs_skip(bs, 8);
PTS_DTS_flags = bs_read(bs, 2);
ESCR_flag = bs_read(bs, 1);
ES_rate_flag = bs_read(bs, 1);
bs_read(bs, 1); // DSM_trick_mode_flag
bs_read(bs, 1); // additional_copy_info_flag
bs_skip(bs, 2);
PES_header_data_length = bs_read(bs, 8);
optional_bytes_remaining = PES_header_data_length;
if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3)
{
bs_skip(bs, 4);
PTS = ts_parser_parse_timestamp(bs);
bs_skip(bs, 1);
optional_bytes_remaining -= 5;
if (PTS_DTS_flags == 3)
{
bs_skip(bs, 4);
DTS = ts_parser_parse_timestamp(bs);
bs_skip(bs, 1);
optional_bytes_remaining -= 5;
}
}
if (ESCR_flag)
{
bs_skip(bs, 2);
ts_parser_parse_timestamp(bs);
bs_skip(bs, 11);
optional_bytes_remaining -= 6;
}
if (ES_rate_flag)
{
bs_skip(bs, 24);
optional_bytes_remaining -= 3;
}
bs_skip(bs, optional_bytes_remaining * 8);
// ES data follows.
if (PES_packet_length != 0)
{
uint32 dataLength = PES_packet_length - 3 - PES_header_data_length;
// Signaling we have payload data
ts_parser_on_payload_data(parser, stream, PTS_DTS_flags, PTS, DTS, bs_data(bs), dataLength);
bs_skip(bs, dataLength * 8);
}
else
{
// Signaling we have payload data
ts_parser_on_payload_data(parser, stream, PTS_DTS_flags, PTS, DTS, bs_data(bs), bs_left(bs) / 8);
}
}
else if (stream_id == 0xbe)
{
// padding_stream
bs_skip(bs, PES_packet_length * 8);
}
else
{
bs_skip(bs, PES_packet_length * 8);
}
}
void ts_parser_flush_stream_data(TSParser * parser, TSStream * stream)
{
bs_t bs;
bs_init(&bs, stream->mBuffer, stream->mBufferSize);
ts_parser_parse_pes(parser, stream, &bs);
stream->mBufferSize = 0;
}
BOOL ts_parser_parse_stream(TSParser * parser, TSStream * stream, uint32 payload_unit_start_indicator, bs_t * bs)
{
uint32 payload_size;
if (payload_unit_start_indicator)
{
if (stream->mPayloadStarted)
{
ts_parser_flush_stream_data(parser, stream);
}
stream->mPayloadStarted = 1;
}
if (!stream->mPayloadStarted)
{
return FALSE;
}
payload_size = bs_left(bs) / 8;
if (stream->mBufferSize + payload_size > ARRAY_SIZE(stream->mBuffer))
{
log_print(HT_LOG_WARN, "%s, packet size(%d) is too big!!!\r\n",
__FUNCTION__, stream->mBufferSize + payload_size);
return FALSE;
}
memcpy(stream->mBuffer + stream->mBufferSize, bs_data(bs), payload_size);
stream->mBufferSize += payload_size;
return TRUE;
}
BOOL ts_parser_parse_program_map(TSParser * parser, TSProgram * program, bs_t * bs)
{
uint32 table_id;
uint32 section_length;
uint32 program_info_length;
size_t infoBytesRemaining;
uint32 streamType;
uint32 elementaryPID;
uint32 ES_info_length;
uint32 info_bytes_remaining;
table_id = bs_read(bs, 8);
if (TS_PMT_TID != table_id)
{
log_print(HT_LOG_ERR, "%s, table_id=%d\r\n", __FUNCTION__, table_id);
return FALSE;
}
bs_read(bs, 1); // section_syntax_indicator
bs_skip(bs, 3); // Reserved
section_length = bs_read(bs, 12);
bs_skip(bs, 16);// program_number
bs_skip(bs, 2); // reserved
bs_skip(bs, 5); // version_number
bs_skip(bs, 1); // current_next_indicator
bs_skip(bs, 8); // section_number
bs_skip(bs, 8); // last_section_number
bs_skip(bs, 3); // reserved
bs_skip(bs, 13);// PCR_PID
bs_skip(bs, 4); // reserved
program_info_length = bs_read(bs, 12);
bs_skip(bs, program_info_length * 8); // skip descriptors
// infoBytesRemaining is the number of bytes that make up the
// variable length section of ES_infos. It does not include the
// final CRC.
infoBytesRemaining = section_length - 9 - program_info_length - 4;
while (infoBytesRemaining > 0)
{
streamType = bs_read(bs, 8);
bs_skip(bs, 3); // reserved
elementaryPID = bs_read(bs, 13);
bs_skip(bs, 4); // reserved
ES_info_length = bs_read(bs, 12);
info_bytes_remaining = ES_info_length;
while (info_bytes_remaining >= 2)
{
uint32 descLength;
bs_skip(bs, 8); // tag
descLength = bs_read(bs, 8);
bs_skip(bs, descLength * 8);
info_bytes_remaining -= descLength + 2;
}
if (ts_parser_get_stream_by_pid(program, elementaryPID) == NULL)
{
ts_parser_add_stream(program, elementaryPID, streamType);
}
infoBytesRemaining -= 5 + ES_info_length;
}
bs_skip(bs, 32); // CRC
return TRUE;
}
BOOL ts_parser_parse_pmt(TSParser * parser, bs_t * bs)
{
size_t i;
uint32 table_id = bs_read(bs, 8);
if (TS_PAT_TID != table_id)
{
log_print(HT_LOG_ERR, "%s, table_id=%d\r\n", __FUNCTION__, table_id);
return FALSE;
}
bs_read(bs, 1); // section_syntax_indicator
bs_skip(bs, 1);
bs_skip(bs, 2); // reserved
uint32 section_length = bs_read(bs, 12);
bs_skip(bs, 16);// transport_stream_id
bs_skip(bs, 2); // reserved
bs_skip(bs, 5); // version_number
bs_skip(bs, 1); // current_next_indicator
bs_skip(bs, 8); // section_number
bs_skip(bs, 8); // last_section_number
size_t numProgramBytes = (section_length - 5 /* header */ - 4 /* crc */);
for (i = 0; i < numProgramBytes / 4; ++i)
{
uint32 program_number = bs_read(bs, 16);
bs_skip(bs, 3); // reserved
if (program_number == 0)
{
bs_skip(bs, 13); // network_PID
}
else
{
uint32 programMapPID = bs_read(bs, 13);
ts_parser_add_program(parser, programMapPID);
}
}
bs_skip(bs, 32); // CRC
return TRUE;
}
BOOL ts_parser_parse_program(TSParser * parser, bs_t * bs, uint32 pid, uint32 payload_unit_start_indicator)
{
BOOL handled = 0;
TSListItem *item;
TSProgram *program;
if (pid == 0)
{
if (payload_unit_start_indicator)
{
uint32 skip = bs_read(bs, 8);
bs_skip(bs, skip * 8);
}
return ts_parser_parse_pmt(parser, bs);
}
for (item = parser->mPrograms.mHead; item != NULL; item = item->mNext)
{
program = (TSProgram *)item->mData;
if (pid == program->mProgramMapPID)
{
if (payload_unit_start_indicator)
{
uint32 skip = bs_read(bs, 8);
bs_skip(bs, skip * 8);
}
handled = ts_parser_parse_program_map(parser, program, bs);
break;
}
else
{
TSStream * pStream = ts_parser_get_stream_by_pid(program, pid);
if (pStream != NULL)
{
handled = ts_parser_parse_stream(parser, pStream, payload_unit_start_indicator, bs);
break;
}
}
}
if (!handled)
{
// log_print(HT_LOG_WARN, "%s, PID 0x%04x not handled.\n", __FUNCTION__, pid);
}
return handled;
}
void ts_parser_parse_adaptation_field(TSParser * parser, bs_t * bs)
{
uint32 adaptation_field_length = bs_read(bs, 8);
if (adaptation_field_length > 0)
{
bs_skip(bs, adaptation_field_length * 8);
}
}
BOOL ts_parser_parse_packet(TSParser * parser, uint8 * data, int size)
{
uint32 transport_error_indicator;
uint32 payload_unit_start_indicator;
uint32 pid;
uint32 adaptation_field_control;
bs_t bs;
bs_init(&bs, data, size);
bs_read(&bs, 8); // sync_byte
transport_error_indicator = bs_read(&bs, 1);
if (transport_error_indicator != 0)
{
log_print(HT_LOG_WARN, "%s, transport error indicator: %u\n",
__FUNCTION__, transport_error_indicator);
}
payload_unit_start_indicator = bs_read(&bs, 1);
bs_read(&bs, 1); // transport_priority
pid = bs_read(&bs, 13);
bs_read(&bs, 2); // transport_scrambling_control
adaptation_field_control = bs_read(&bs, 2);
bs_read(&bs, 4); // continuity_counter
if (adaptation_field_control == 2 || adaptation_field_control == 3)
{
ts_parser_parse_adaptation_field(parser, &bs);
}
if (adaptation_field_control == 1 || adaptation_field_control == 3)
{
ts_parser_parse_program(parser, &bs, pid, payload_unit_start_indicator);
}
return TRUE;
}
BOOL ts_parser_parse(TSParser * parser, uint8 * data, int size)
{
for (;;)
{
if (size == 0)
{
break;
}
else if (size < TS_PACKET_SIZE)
{
return FALSE;
}
if (data[0] != TS_SYNC)
{
data++;
size--;
}
else
{
if (!ts_parser_parse_packet(parser, data, TS_PACKET_SIZE))
{
return FALSE;
}
data += TS_PACKET_SIZE;
size -= TS_PACKET_SIZE;
}
}
return TRUE;
}
BOOL ts_parser_init(TSParser * parser)
{
if (NULL == parser)
{
return FALSE;
}
memset(parser, 0, sizeof(TSParser));
parser->mMutex = sys_os_create_mutex();
return TRUE;
}
void ts_parser_set_cb(TSParser * parser, payload_cb cb, void * userdata)
{
if (NULL == parser)
{
return;
}
sys_os_mutex_enter(parser->mMutex);
parser->mCallback = cb;
parser->mUserdata = userdata;
sys_os_mutex_leave(parser->mMutex);
}
void ts_parser_free_program(TSProgram * program)
{
// Free Streams
TSListItem *item;
TSStream *stream;
while (program->mStreams.mHead != NULL)
{
item = program->mStreams.mHead;
program->mStreams.mHead = item->mNext;
if(item->mData != NULL)
{
stream = (TSStream *)item->mData;
free(stream);
}
free(item);
}
}
void ts_parser_free(TSParser * parser)
{
// Free Programs
TSListItem *item;
TSProgram *program;
while (parser->mPrograms.mHead != NULL)
{
item = parser->mPrograms.mHead;
parser->mPrograms.mHead = item->mNext;
if (item->mData != NULL)
{
program = (TSProgram *)item->mData;
ts_parser_free_program(program);
free(program);
}
free(item);
}
sys_os_destroy_sig_mutex(parser->mMutex);
}

100
MediaClient/rtp/ts_parser.h Normal file
View File

@@ -0,0 +1,100 @@
/***************************************************************************************
*
* 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.
*
****************************************************************************************/
#ifndef TS_PARSER_H
#define TS_PARSER_H
#include "sys_inc.h"
#define TS_PACKET_SIZE 188
#define TS_SYNC 0x47
#define TS_DISCONTINUITY 0x0
#define TS_PAT_TID 0x00
#define TS_PMT_TID 0x02
#define TS_STREAM_VIDEO 0x1b
#define TS_STREAM_AUDIO 0x0f
#define TS_AUDIO_AAC 0x0f
#define TS_AUDIO_AAC_LATM 0x11
#define TS_VIDEO_MPEG4 0x10
#define TS_VIDEO_H264 0x1b
#define TS_VIDEO_HEVC 0x24
typedef void (*payload_cb)(uint8 *, uint32, uint32, uint64, void *);
typedef struct _TSListItem
{
void *mData;
struct _TSListItem *mNext;
} TSListItem;
typedef struct _TSList
{
TSListItem *mHead;
TSListItem *mTail;
} TSList;
typedef struct
{
uint32 mProgramMapPID;
uint64 mFirstPTS;
int mFirstPTSValid;
TSList mStreams;
} TSProgram;
typedef struct
{
TSProgram *mProgram;
uint32 mElementaryPID;
uint32 mStreamType;
uint32 mPayloadStarted;
char mBuffer[2*1024*1024];
int mBufferSize;
} TSStream;
typedef struct
{
TSList mPrograms;
payload_cb mCallback;
void *mUserdata;
void *mMutex;
} TSParser;
#ifdef __cplusplus
extern "C" {
#endif
BOOL ts_parser_init(TSParser * parser);
void ts_parser_set_cb(TSParser * parser, payload_cb cb, void * userdata);
BOOL ts_parser_parse(TSParser * parser, uint8 * data, int size);
BOOL ts_parser_parse_packet(TSParser * parser, uint8 * data, int size);
void ts_parser_free(TSParser * parser);
#ifdef __cplusplus
}
#endif
#endif