multimedia/device/mpp/sample/hisi_rtsp_demo-master/rtsp_lib/utils.c

456 lines
12 KiB
C

/*************************************************************************
> File Name: utils.c
> Author: bxq
> Mail: 544177215@qq.com
> Created Time: Sunday, May 22, 2016 PM09:35:22 CST
************************************************************************/
#include <string.h>
#include "comm.h"
#include "utils.h"
/*****************************************************************************
* b64_encode: Stolen from VLC's http.c.
* Simplified by Michael.
* Fixed edge cases and made it work from data (vs. strings) by Ryan.
*****************************************************************************/
static char *base64_encode (char *out, int out_size, const uint8_t *in, int in_size)
{
static const char b64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char *ret, *dst;
unsigned i_bits = 0;
int i_shift = 0;
int bytes_remaining = in_size;
#define __UINT_MAX (~0lu)
#define __BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1)
#define __RB32(x) \
(((uint32_t)((const uint8_t*)(x))[0] << 24) | \
(((const uint8_t*)(x))[1] << 16) | \
(((const uint8_t*)(x))[2] << 8) | \
((const uint8_t*)(x))[3])
if (in_size >= __UINT_MAX / 4 ||
out_size < __BASE64_SIZE(in_size))
return NULL;
ret = dst = out;
while (bytes_remaining > 3) {
i_bits = __RB32(in);
in += 3; bytes_remaining -= 3;
*dst++ = b64[ i_bits>>26 ];
*dst++ = b64[(i_bits>>20) & 0x3F];
*dst++ = b64[(i_bits>>14) & 0x3F];
*dst++ = b64[(i_bits>>8 ) & 0x3F];
}
i_bits = 0;
while (bytes_remaining) {
i_bits = (i_bits << 8) + *in++;
bytes_remaining--;
i_shift += 8;
}
while (i_shift > 0) {
*dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f];
i_shift -= 6;
}
while ((dst - ret) & 3)
*dst++ = '=';
*dst = '\0';
return ret;
}
const uint8_t *rtsp_find_h264_h265_nalu (const uint8_t *buff, int len, int *size)
{
const uint8_t *s = NULL;
while (len >= 3) {
if (buff[0] == 0 && buff[1] == 0 && buff[2] == 1) {
if (!s) {
if (len < 4)
return NULL;
s = buff;
} else {
*size = (buff - s);
return s;
}
buff += 3;
len -= 3;
continue;
}
if (len >= 4 && buff[0] == 0 && buff[1] == 0 && buff[2] == 0 && buff[3] == 1) {
if (!s) {
if (len < 5)
return NULL;
s = buff;
} else {
*size = (buff - s);
return s;
}
buff += 4;
len -= 4;
continue;
}
buff ++;
len --;
}
if (!s)
return NULL;
*size = (buff - s + len);
return s;
}
const uint8_t *rtsp_find_aac_adts (const uint8_t *buff, int len, int *size)
{
const uint8_t *s = buff;
while (len > 2) {
if (s[0] == 0xff && (s[1] & 0xf0) == 0xf0) {
break;
}
buff ++;
len --;
}
if (len <= 2)
return NULL;
//aac_frame_length
*size = 0;
*size |= (s[3] & 3) << 11;
*size |= (s[4] << 3);
*size |= (s[5] >> 5);
if (*size > len)
return NULL;
return s;
}
int rtsp_codec_data_parse_from_user_h264 (const uint8_t *codec_data, int data_len, struct codec_data_h264 *pst_codec_data)
{
const uint8_t *s = codec_data;
const uint8_t *frame = NULL;
int len = data_len;
int size = 0;
int ret = 0;
while (len > 3) {
uint8_t type = 0;
if (pst_codec_data->sps_len > 0 && pst_codec_data->pps_len > 0) {
break;
}
frame = rtsp_find_h264_h265_nalu(s, len, &size);
if (!frame) {
break;
}
len = len - (frame - s + size);
s = frame + size;
if (frame[2] == 0) {
frame += 4; //drop 0001
size -= 4;
} else {
frame += 3; //drop 001
size -= 3;
}
type = frame[0] & 0x1f;
if (type == 7) {
dbg("sps %d\n", size);
if (size > (int)sizeof(pst_codec_data->sps))
size = sizeof(pst_codec_data->sps);
memcpy(pst_codec_data->sps, frame, size);
pst_codec_data->sps_len = size;
ret ++;
}
if (type == 8) {
dbg("pps %d\n", size);
if (size > (int)sizeof(pst_codec_data->pps))
size = sizeof(pst_codec_data->pps);
memcpy(pst_codec_data->pps, frame, size);
pst_codec_data->pps_len = size;
ret ++;
}
}
return (ret >= 2 ? 1 : 0);
}
int rtsp_codec_data_parse_from_user_h265 (const uint8_t *codec_data, int data_len, struct codec_data_h265 *pst_codec_data)
{
const uint8_t *s = codec_data;
const uint8_t *frame = NULL;
int len = data_len;
int size = 0;
int ret = 0;
while (len > 3) {
uint8_t type = 0;
if (pst_codec_data->vps_len > 0 && pst_codec_data->sps_len > 0 && pst_codec_data->pps_len > 0) {
break;
}
frame = rtsp_find_h264_h265_nalu(s, len, &size);
if (!frame) {
break;
}
len = len - (frame - s + size);
s = frame + size;
if (frame[2] == 0) {
frame += 4; //drop 0001
size -= 4;
} else {
frame += 3; //drop 001
size -= 3;
}
type = (frame[0] >> 1) & 0x3f;
if (type == 32) {
dbg("vps %d\n", size);
if (size > (int)sizeof(pst_codec_data->vps))
size = sizeof(pst_codec_data->vps);
memcpy(pst_codec_data->vps, frame, size);
pst_codec_data->vps_len = size;
ret ++;
}
if (type == 33) {
dbg("sps %d\n", size);
if (size > (int)sizeof(pst_codec_data->sps))
size = sizeof(pst_codec_data->sps);
memcpy(pst_codec_data->sps, frame, size);
pst_codec_data->sps_len = size;
ret ++;
}
if (type == 34) {
dbg("pps %d\n", size);
if (size > (int)sizeof(pst_codec_data->pps))
size = sizeof(pst_codec_data->pps);
memcpy(pst_codec_data->pps, frame, size);
pst_codec_data->pps_len = size;
ret ++;
}
}
return (ret >= 3 ? 1 : 0);
}
int rtsp_codec_data_parse_from_user_g726 (const uint8_t *codec_data, int data_len, struct codec_data_g726 *pst_codec_data)
{
int bit_rate;
if (data_len != sizeof(bit_rate)) {
err("bit rate invalid\n");
return -1;
}
bit_rate = *((int*)codec_data);
switch (bit_rate) {
case 16000:
case 24000:
case 32000:
case 40000:
break;
default:
err("bit rate invalid\n");
return -1;
}
pst_codec_data->bit_rate = bit_rate;
return 1;
}
int rtsp_codec_data_parse_from_user_aac (const uint8_t *codec_data, int data_len, struct codec_data_aac *pst_codec_data)
{
int sample_rate_index, channels;
const uint32_t sample_rate_tbl[16] = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0, 0, 0};
if (data_len != 2) {
err("audio specific config invalid\n");
return -1;
}
sample_rate_index = ((codec_data[0] & 0x7) << 1) | (codec_data[1] >> 7);
channels = (codec_data[1] >> 3) & 0x0f;
if (sample_rate_index > 12 && channels > 7) {
err("audio specific config invalid\n");
return -1;
}
memcpy(pst_codec_data->audio_specific_config, codec_data, data_len);
pst_codec_data->audio_specific_config_len = data_len;
pst_codec_data->sample_rate = sample_rate_tbl[sample_rate_index];
pst_codec_data->channels = (channels == 7) ? 8 : channels;
dbg("config=%02X%02X sample_rate=%d channels=%d\n",
pst_codec_data->audio_specific_config[0], pst_codec_data->audio_specific_config[1],
sample_rate_tbl[sample_rate_index], channels);
return 1;
}
int rtsp_codec_data_parse_from_frame_h264 (const uint8_t *frame, int len, struct codec_data_h264 *pst_codec_data)
{
return rtsp_codec_data_parse_from_user_h264(frame, len, pst_codec_data);
}
int rtsp_codec_data_parse_from_frame_h265 (const uint8_t *frame, int len, struct codec_data_h265 *pst_codec_data)
{
return rtsp_codec_data_parse_from_user_h265(frame, len, pst_codec_data);
}
int rtsp_codec_data_parse_from_frame_aac (const uint8_t *frame, int len, struct codec_data_aac *pst_codec_data)
{
int profile, sample_rate_index, channels;
const uint32_t sample_rate_tbl[16] = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0, 0, 0};
int size = 0;
if (pst_codec_data->audio_specific_config_len > 0)
return 0;
frame = rtsp_find_aac_adts(frame, len, &size);
if (!frame) {
err("find adts header failed\n");
return -1;
}
profile = frame[2] >> 6;
sample_rate_index = (frame[2] >> 2) & 0x0f;
channels = ((frame[2] & 0x1) << 1) | (frame[3] >> 6);
if (sample_rate_index > 12 && channels > 7) {
err("audio specific config invalid\n");
return -1;
}
pst_codec_data->audio_specific_config[0] = ((profile + 1) << 3) | ((sample_rate_index >> 1) & 0x7);
pst_codec_data->audio_specific_config[1] = ((sample_rate_index & 0x1) << 7) | (channels << 3);
pst_codec_data->audio_specific_config_len = 2;
pst_codec_data->sample_rate = sample_rate_tbl[sample_rate_index];
pst_codec_data->channels = (channels == 7) ? 8 : channels;
dbg("config=%02X%02X sample_rate=%d channels=%d\n",
pst_codec_data->audio_specific_config[0], pst_codec_data->audio_specific_config[1],
sample_rate_tbl[sample_rate_index], channels);
return 1;
}
int rtsp_build_sdp_media_attr_h264 (int pt, int sample_rate, const struct codec_data_h264 *pst_codec_data, char *sdpbuf, int maxlen)
{
char *p = sdpbuf;
// dbg("\n");
p += sprintf(p, "m=video 0 RTP/AVP %d\r\n", pt);
p += sprintf(p, "c=IN IP4 0.0.0.0\r\n");
p += sprintf(p, "a=rtpmap:%d H264/%d\r\n", pt, sample_rate);
if (pst_codec_data->sps_len > 0 && pst_codec_data->pps_len > 0) {
const uint8_t *sps = pst_codec_data->sps;
const uint8_t *pps = pst_codec_data->pps;
int sps_len = pst_codec_data->sps_len;
int pps_len = pst_codec_data->pps_len;
p += sprintf(p, "a=fmtp:%d packetization-mode=1;sprop-parameter-sets=", pt);
base64_encode(p, (maxlen - (p - sdpbuf)), sps, sps_len);
p += strlen(p);
p += sprintf(p, ",");
base64_encode(p, (maxlen - (p - sdpbuf)), pps, pps_len);
p += strlen(p);
p += sprintf(p, "\r\n");
} else {
p += sprintf(p, "a=fmtp:%d packetization-mode=1\r\n", pt);
}
return (p - sdpbuf);
}
int rtsp_build_sdp_media_attr_h265 (int pt, int sample_rate, const struct codec_data_h265 *pst_codec_data, char *sdpbuf, int maxlen)
{
char *p = sdpbuf;
// dbg("\n");
p += sprintf(p, "m=video 0 RTP/AVP %d\r\n", pt);
p += sprintf(p, "c=IN IP4 0.0.0.0\r\n");
p += sprintf(p, "a=rtpmap:%d H265/%d\r\n", pt, sample_rate);
if (pst_codec_data->vps_len > 0 && pst_codec_data->sps_len > 0 && pst_codec_data->pps_len > 0) {
const uint8_t *vps = pst_codec_data->vps;
const uint8_t *sps = pst_codec_data->sps;
const uint8_t *pps = pst_codec_data->pps;
int vps_len = pst_codec_data->vps_len;
int sps_len = pst_codec_data->sps_len;
int pps_len = pst_codec_data->pps_len;
p += sprintf(p, "a=fmtp:%d", pt);
p += sprintf(p, " sprop-vps=");
base64_encode(p, (maxlen - (p - sdpbuf)), vps, vps_len);
p += strlen(p);
p += sprintf(p, ";sprop-sps=");
base64_encode(p, (maxlen - (p - sdpbuf)), sps, sps_len);
p += strlen(p);
p += sprintf(p, ";sprop-pps=");
base64_encode(p, (maxlen - (p - sdpbuf)), pps, pps_len);
p += strlen(p);
p += sprintf(p, "\r\n");
}
return (p - sdpbuf);
}
int rtsp_build_sdp_media_attr_g711a (int pt, int sample_rate, char *sdpbuf, int maxlen)
{
char *p = sdpbuf;
// dbg("\n");
p += sprintf(p, "m=audio 0 RTP/AVP %d\r\n", pt);
p += sprintf(p, "c=IN IP4 0.0.0.0\r\n");
p += sprintf(p, "a=rtpmap:%d PCMA/%d/1\r\n", pt, sample_rate);
return (p - sdpbuf);
}
int rtsp_build_sdp_media_attr_g711u (int pt, int sample_rate, char *sdpbuf, int maxlen)
{
char *p = sdpbuf;
// dbg("\n");
p += sprintf(p, "m=audio 0 RTP/AVP %d\r\n", pt);
p += sprintf(p, "c=IN IP4 0.0.0.0\r\n");
p += sprintf(p, "a=rtpmap:%d PCMU/%d/1\r\n", pt, sample_rate);
return (p - sdpbuf);
}
int rtsp_build_sdp_media_attr_g726 (int pt, int sample_rate, const struct codec_data_g726 *pst_codec_data, char *sdpbuf, int maxlen)
{
char *p = sdpbuf;
// dbg("\n");
p += sprintf(p, "m=audio 0 RTP/AVP %d\r\n", pt);
p += sprintf(p, "c=IN IP4 0.0.0.0\r\n");
p += sprintf(p, "a=rtpmap:%d G726-%d/%d/1\r\n", pt,
pst_codec_data->bit_rate ? pst_codec_data->bit_rate / 1000 : 32,
sample_rate);
return (p - sdpbuf);
}
int rtsp_build_sdp_media_attr_aac (int pt, int sample_rate, const struct codec_data_aac *pst_codec_data, char *sdpbuf, int maxlen)
{
char *p = sdpbuf;
// dbg("\n");
p += sprintf(p, "m=audio 0 RTP/AVP %d\r\n", pt);
p += sprintf(p, "c=IN IP4 0.0.0.0\r\n");
p += sprintf(p, "a=rtpmap:%d MPEG4-GENERIC/%d/%d\r\n", pt,
pst_codec_data->sample_rate ? pst_codec_data->sample_rate : 44100,
pst_codec_data->channels ? pst_codec_data->channels : 2);
if (pst_codec_data->audio_specific_config_len == 2) {
p += sprintf(p, "a=fmtp:%d profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=%02X%02X\r\n",
pt, pst_codec_data->audio_specific_config[0], pst_codec_data->audio_specific_config[1]);
} else {
p += sprintf(p, "a=fmtp:%d profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3\r\n", pt);
}
return (p - sdpbuf);
}