Skip to content

Commit

Permalink
Starting to support HEVC on the RTSP server
Browse files Browse the repository at this point in the history
  • Loading branch information
wberube committed Jun 18, 2024
1 parent 54da498 commit 70f1089
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 54 deletions.
5 changes: 3 additions & 2 deletions src/media.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ int save_video_stream(char index, hal_vidstream *stream) {
struct timeval tv = {
.tv_sec = stream->pack[i].timestamp / 1000000,
.tv_usec = stream->pack[i].timestamp % 1000000 };
rtp_send_h264(rtspHandle, stream->pack[i].data + stream->pack[i].offset,
stream->pack[i].length - stream->pack[i].offset, &tv);
rtp_send_h26x(rtspHandle, stream->pack[i].data + stream->pack[i].offset,
stream->pack[i].length - stream->pack[i].offset, &tv,
chnState[index].payload == HAL_VIDCODEC_H265 ? 1 : 0);
}
}
break;
Expand Down
10 changes: 5 additions & 5 deletions src/rtsp/rfc.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@
#define RTP_SEQ_MOD (1<<16)
#define RTP_MAX_SDES 255 /* maximum text length for SDES */

#define H264_NAL_TYPE_NON_IDR 1
#define H264_NAL_TYPE_SLICE_A 2
#define H264_NAL_TYPE_SLICE_B 3
#define H264_NAL_TYPE_SLICE_C 4
#define H264_NAL_TYPE_IDR 5
#define H264_NAL_TYPE_SEI 6
#define H264_NAL_TYPE_SPS 7
#define H264_NAL_TYPE_PPS 8
#define H265_NAL_TYPE_VPS 32
#define H265_NAL_TYPE_SPS 33
#define H265_NAL_TYPE_PPS 34
#define H265_NAL_TYPE_SEIP 39
#define H265_NAL_TYPE_SEIS 40

typedef enum {
RTCP_SR = 200,
Expand Down
120 changes: 78 additions & 42 deletions src/rtsp/rtp.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
* PRIVATE DEFINITIONS
******************************************************************************/
//static void *rtpThrFxn(void *v);
static inline int __rtp_send_h264(struct nal_rtp_t *rtp, struct list_head_t *trans_list);
static inline int __rtp_send_eachconnection_h264(struct list_t *e, void *v);
static inline int __rtp_send_h26x(struct nal_rtp_t *rtp, struct list_head_t *trans_list);
static inline int __rtp_send_eachconnection_h26x(struct list_t *e, void *v);
static inline int __rtp_setup_transfer(struct list_t *e, void *v);
static inline int __transfer_nal(struct list_head_t *trans_list, unsigned char *nalptr, size_t nalsize);
static inline int __transfer_nal_h26x(struct list_head_t *trans_list, unsigned char *nalptr, size_t nalsize, char isH265);
static inline int __retrieve_sprop(rtsp_handle h, unsigned char *buf, size_t len);

struct __transfer_set_t {
Expand All @@ -37,11 +37,14 @@ struct __transfer_set_t {
* PRIVATE FUNCTIONS
******************************************************************************/

static inline int __transfer_nal(struct list_head_t *trans_list, unsigned char *nalptr, size_t nalsize)
static inline int __transfer_nal_h26x(struct list_head_t *trans_list, unsigned char *nalptr, size_t nalsize, char isH265)
{
struct nal_rtp_t rtp;
unsigned int nri = nalptr[0] & 0x60;
unsigned int pt = nalptr[0] & 0x1F;
unsigned int nri = isH265 ? (nalptr[0] & 0x81) : (nalptr[0] & 0x60);
unsigned int pt = isH265 ? (nalptr[0] & 0x7E >> 1) : (nalptr[0] & 0x1F);
unsigned int ids = isH265 ? nalptr[1] : 0;
char head = isH265 ? 3 : 2;

rtp_hdr_t *p_header = &(rtp.packet.header);
unsigned char *payload = rtp.packet.payload;

Expand All @@ -54,7 +57,11 @@ static inline int __transfer_nal(struct list_head_t *trans_list, unsigned char *
if(nalsize <= __RTP_MAXPAYLOADSIZE){
/* single packet */
/* SPS, PPS, SEI is not marked */
if(pt != 7 && pt != 8 && pt != 6) {
if ((isH265 && pt < H265_NAL_TYPE_VPS) ||
(!isH265 &&
pt != H264_NAL_TYPE_SPS &&
pt != H264_NAL_TYPE_PPS &&
pt != H264_NAL_TYPE_SEI)) {
p_header->m = 1;
} else {
p_header->m = 0;
Expand All @@ -64,55 +71,60 @@ static inline int __transfer_nal(struct list_head_t *trans_list, unsigned char *

rtp.rtpsize = nalsize + sizeof(rtp_hdr_t);

ASSERT(__rtp_send_h264(&rtp,trans_list) == SUCCESS, return FAILURE);
ASSERT(__rtp_send_h26x(&rtp,trans_list) == SUCCESS, return FAILURE);
} else {

nalptr += 1;
nalsize -= 1;

payload[0] = 28;
payload[0] |= nri;
payload[1] = pt;
payload[1] |= 1 << 7;
nalptr += isH265 ? 2 : 1;
nalsize -= isH265 ? 2 : 1;

if (isH265) {
payload[0] = 49 << 1;
payload[0] |= nri;
payload[1] = ids;
payload[2] = pt;
} else {
payload[0] = 28;
payload[0] |= nri;
payload[1] = pt;
}
payload[head - 1] |= 1 << 7;

/* send fragmented nal */
while(nalsize > __RTP_MAXPAYLOADSIZE - 2){

while(nalsize > __RTP_MAXPAYLOADSIZE - head){
p_header->m = 0;

memcpy(&(payload[2]), nalptr, __RTP_MAXPAYLOADSIZE - 2);
memcpy(&(payload[head]), nalptr, __RTP_MAXPAYLOADSIZE - head);

rtp.rtpsize = sizeof(rtp_hdr_t) + __RTP_MAXPAYLOADSIZE;

nalptr += __RTP_MAXPAYLOADSIZE - 2;
nalsize -= __RTP_MAXPAYLOADSIZE - 2;
nalptr += __RTP_MAXPAYLOADSIZE - head;
nalsize -= __RTP_MAXPAYLOADSIZE - head;

ASSERT(__rtp_send_h264(&rtp,trans_list) == SUCCESS, return FAILURE);
ASSERT(__rtp_send_h26x(&rtp,trans_list) == SUCCESS, return FAILURE);

/* intended xor. blame vim :( */
payload[1] &= 0xFF ^ (1<<7);
payload[head - 1] &= 0xFF ^ (1<<7);
}

/* send trailing nal */
p_header->m = 1;

payload[1] |= 1 << 6;
payload[head - 1] |= 1 << 6;

/* intended xor. blame vim :( */
payload[1] &= 0xFF ^ (1<<7);
payload[head - 1] &= 0xFF ^ (1<<7);

rtp.rtpsize = nalsize + sizeof(rtp_hdr_t);

memcpy(&(payload[2]), nalptr, nalsize);
memcpy(&(payload[head]), nalptr, nalsize);

ASSERT(__rtp_send_h264(&rtp, trans_list) == SUCCESS, return FAILURE);
ASSERT(__rtp_send_h26x(&rtp, trans_list) == SUCCESS, return FAILURE);

}

return SUCCESS;
}

static inline int __rtp_send_eachconnection_h264(struct list_t *e, void *v)
static inline int __rtp_send_eachconnection_h26x(struct list_t *e, void *v)
{
int send_bytes;
struct connection_item_t *con;
Expand Down Expand Up @@ -150,9 +162,9 @@ static inline int __rtp_send_eachconnection_h264(struct list_t *e, void *v)
return FAILURE;
}

static inline int __rtp_send_h264(struct nal_rtp_t *rtp, struct list_head_t *trans_list)
static inline int __rtp_send_h26x(struct nal_rtp_t *rtp, struct list_head_t *trans_list)
{
return list_map_inline(trans_list,(__rtp_send_eachconnection_h264), rtp);
return list_map_inline(trans_list,(__rtp_send_eachconnection_h26x), rtp);
}


Expand Down Expand Up @@ -202,16 +214,42 @@ static inline int __retrieve_sprop(rtsp_handle h, unsigned char *buf, size_t len
size_t single_len;
mime_encoded_handle base64 = NULL;
mime_encoded_handle base16 = NULL;
unsigned int pt;


/* check VPS is set */
if(!(h->sprop_vps_b64)){
nalptr = buf;
single_len = 0;
while (__split_nal(buf,&nalptr,&single_len,len) == SUCCESS) {
if (nalptr[0] & 0x7E >> 1 == H265_NAL_TYPE_VPS) {
ASSERT(single_len >= 4, return FAILURE);
ASSERT(base64 = mime_base64_create((char *)&(nalptr[0]),single_len), return FAILURE);

DASSERT(base64->base == 64, return FAILURE);

/* optimistic lock */
rtsp_lock(h);
if(h->sprop_vps_b64) {
DBG("pps is set by another thread?\n");
mime_encoded_delete(base64);
} else {
h->sprop_vps_b64 = base64;
}
rtsp_unlock(h);
}
}
rtsp_lock(h);
rtsp_unlock(h);
base64 = NULL;
}

/* check SPS is set */
if(!(h->sprop_sps_b64)){
nalptr = buf;
single_len = 0;

while (__split_nal(buf,&nalptr,&single_len,len) == SUCCESS) {
pt = nalptr[0] & 0x1F;
if(pt == H264_NAL_TYPE_SPS) {
if (nalptr[0] & 0x1F == H264_NAL_TYPE_SPS ||
nalptr[0] & 0x7E >> 1 == H265_NAL_TYPE_SPS) {
ASSERT(base64 = mime_base64_create((char *)&(nalptr[0]),single_len), return FAILURE);
ASSERT(base16 = mime_base16_create((char *)&(nalptr[1]),3), return FAILURE);

Expand All @@ -235,7 +273,6 @@ static inline int __retrieve_sprop(rtsp_handle h, unsigned char *buf, size_t len
}
rtsp_unlock(h);
}

}

base64 = NULL;
Expand All @@ -247,9 +284,8 @@ static inline int __retrieve_sprop(rtsp_handle h, unsigned char *buf, size_t len
nalptr = buf;
single_len = 0;
while (__split_nal(buf,&nalptr,&single_len,len) == SUCCESS) {
pt = nalptr[0] & 0x1F;

if(pt == H264_NAL_TYPE_PPS) {
if (nalptr[0] & 0x1F == H264_NAL_TYPE_PPS ||
nalptr[0] & 0x7E >> 1 == H265_NAL_TYPE_PPS) {
ASSERT(single_len >= 4, return FAILURE);
ASSERT(base64 = mime_base64_create((char *)&(nalptr[0]),single_len), return FAILURE);

Expand Down Expand Up @@ -295,7 +331,7 @@ static inline int __rtcp_poll(struct list_t *e, void *v)
/******************************************************************************
* PUBLIC FUNCTIONS
******************************************************************************/
int rtp_send_h264(rtsp_handle h, unsigned char *buf, size_t len, struct timeval *p_tv)
int rtp_send_h26x(rtsp_handle h, unsigned char *buf, size_t len, struct timeval *p_tv, char isH265)
{
unsigned char *nalptr = buf;
size_t single_len = 0;
Expand All @@ -306,15 +342,15 @@ int rtp_send_h264(rtsp_handle h, unsigned char *buf, size_t len, struct timeval
DASSERT(h, return FAILURE);
DASSERT(p_tv, return FAILURE);


if(gbl_get_quit(h->pool->sharedp->gbl)) {
ERR("server threads have gone already. call rtsp_finish()\n");
return FAILURE;
}

__get_timestamp_offset(&h->stat, p_tv);


h->isH265 = isH265;

ASSERT(__retrieve_sprop(h,buf,len) == SUCCESS, goto error);

trans.h = h;
Expand All @@ -326,7 +362,7 @@ int rtp_send_h264(rtsp_handle h, unsigned char *buf, size_t len, struct timeval

while (__split_nal(buf,&nalptr,&single_len,len) == SUCCESS) {

ASSERT(__transfer_nal(&(trans.list_head),nalptr,single_len) == SUCCESS, goto error);
ASSERT(__transfer_nal_h26x(&(trans.list_head),nalptr,single_len,h->isH265) == SUCCESS, goto error);

}

Expand Down
38 changes: 34 additions & 4 deletions src/rtsp/rtsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,16 +257,46 @@ static void __method_describe(struct connection_item_t *p, rtsp_handle h)
{
char sdp[__RTSP_TCP_BUF_SIZE];

if(h->sprop_sps_b64 && h->sprop_sps_b16 && h->sprop_pps_b64) {
if (h->isH265 &&
h->sprop_vps_b64 && h->sprop_sps_b64 && h->sprop_sps_b16 && h->sprop_pps_b64) {
DASSERT(h->sprop_vps_b64->result, return);
DASSERT(h->sprop_sps_b64->result, return);
DASSERT(h->sprop_sps_b16->result, return);
DASSERT(h->sprop_pps_b64->result, return);

DBG("VPS BASE64:%s\n",h->sprop_vps_b64->result);
DBG("SPS BASE64:%s\n",h->sprop_sps_b64->result);
DBG("SPS BASE16:%s\n",h->sprop_sps_b16->result);
DBG("PPS BASE64:%s\n",h->sprop_pps_b64->result);

snprintf(sdp, __RTSP_TCP_BUF_SIZE- 1,
"v=0\r\n"
"o=- 0 0 IN IP4 127.0.0.1\r\n"
"s=librtsp\r\n"
"c=IN IP4 0.0.0.0\r\n"
"t=0 0\r\n"
"a=tool:libavformat 52.73.0\r\n"
"m=video 0 RTP/AVP 96\r\n"
"a=rtpmap:96 H265/90000\r\n"
"a=control:stream=0\r\n"
"a=fmtp:96 packetization-mode=1;"
" profile-level-id=%s;"
" sprop-parameter-sets=%s,%s,%s;\r\n",
h->sprop_sps_b16->result,
h->sprop_vps_b64->result,
h->sprop_sps_b64->result,
h->sprop_pps_b64->result);
} else if (!h->isH265 &&
h->sprop_sps_b64 && h->sprop_sps_b16 && h->sprop_pps_b64) {
DASSERT(h->sprop_sps_b64->result, return);
DASSERT(h->sprop_sps_b16->result, return);
DASSERT(h->sprop_pps_b64->result, return);

DBG("SPS BASE64:%s\n",h->sprop_sps_b64->result);
DBG("SPS BASE16:%s\n",h->sprop_sps_b16->result);
DBG("PPS BASE64:%s\n",h->sprop_pps_b64->result);

snprintf(sdp, __RTSP_TCP_BUF_SIZE - 1,
"v=0\r\n"
"o=- 0 0 IN IP4 127.0.0.1\r\n"
"s=librtsp\r\n"
Expand All @@ -283,17 +313,17 @@ static void __method_describe(struct connection_item_t *p, rtsp_handle h)
h->sprop_sps_b64->result,
h->sprop_pps_b64->result);
} else {
strncpy(sdp,
snprintf(sdp, __RTSP_TCP_BUF_SIZE - 1,
"v=0\r\n"
"o=- 0 0 IN IP4 127.0.0.1\r\n"
"s=librtsp\r\n"
"c=IN IP4 0.0.0.0\r\n"
"t=0 0\r\n"
"a=tool:libavformat 52.73.0\r\n"
"m=video 0 RTP/AVP 96\r\n"
"a=rtpmap:96 H264/90000\r\n"
"a=rtpmap:96 %s/90000\r\n"
"a=fmtp:96 packetization-mode=1\r\n"
"a=control:stream=0\r\n", __RTSP_TCP_BUF_SIZE - 1);
"a=control:stream=0\r\n", h->isH265 ? "H265" : "H264");
}

fprintf(p->fp_tcp_write, "RTSP/1.0 200 OK\r\n"
Expand Down
2 changes: 2 additions & 0 deletions src/rtsp/rtsp.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ struct __rtsp_obj_t {
bufpool_handle transfer_pool;
unsigned short port;
struct __time_stat_t stat;
char isH265;
mime_encoded_handle sprop_vps_b64;
mime_encoded_handle sprop_sps_b64;
mime_encoded_handle sprop_pps_b64;
mime_encoded_handle sprop_sps_b16;
Expand Down
2 changes: 1 addition & 1 deletion src/rtsp/rtsp_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ typedef struct __rtsp_obj_t *rtsp_handle;
/* put virtual pointer to 'buf', which consists of 1 or more NALUs (start code required).
SPS and PPS parameters are automatically collected during execution. */

int rtp_send_h264(rtsp_handle h, unsigned char *buf, size_t len, struct timeval *p_tv);
int rtp_send_h26x(rtsp_handle h, unsigned char *buf, size_t len, struct timeval *p_tv, char isH265);

extern void rtsp_finish(rtsp_handle h);

Expand Down

0 comments on commit 70f1089

Please sign in to comment.