rtp
实时传输协议,可以使用udp和tcp
h264 和 h265
h264有sps pps,se 帧,h265多一些,有sps pps vps等,不过不是很重要,接收的时候用的多一些,发送稍简单,以下是发送程序
mtu
最大传输单元,不管是tcp还是udp都必须要分包发送,因为超过mtu实际上被交换机等设备分帧,所以必须小于交换机等设备的最大传输单元,这样效率比较高。一般我们可以定义mtu为1400字节,当然可以再小一点,加上rtp协议头部的12字节,最多为1412字节,各位可以自己拟定。
网络发送
这一部分可以使用各类封装程序,也可以自己调用简单的socket api函数发送,具体不细节写了,读者可以自己用喜欢的程序来完成
void rtp_send_data(uint8_t *buf, int len, int last_packet_of_frame,uint32_t timestamp)
{
}
发送rtp for h264
分为h264和h265
void send_rtp_h264(uint8_t * data, int dlen,uint32_t timestamp)
{
int iSize = max_payload_size- RTP_HEADERS_SIZE;
uint8_t buf[max_payload_size];
uint8_t *pos = &buf[12];
if (dlen > iSize) {
const uint8_t s_e_r_Start = 0x80;
const uint8_t s_e_r_Mid = 0x00;
const uint8_t s_e_r_End = 0x40;
unsigned char naluType = (*data) & 0x1f;
unsigned char nal_ref_idc = (*data) & 0x60;
unsigned char f_nri_type = nal_ref_idc + 28;
unsigned char s_e_r_type = naluType;
bool bFirst = true;
bool mark = false;
int nOffset = 1;
while (!mark) {
if (dlen < nOffset + iSize) {
iSize = dlen - nOffset;
mark = true;
s_e_r_type = s_e_r_End + naluType;
}
else {
if (bFirst == true) {
s_e_r_type = s_e_r_Start + naluType;
bFirst = false;
}
else {
s_e_r_type = s_e_r_Mid + naluType;
}
}
*pos = f_nri_type;
*(pos + 1) = s_e_r_type;
memcpy(pos + 2, data + nOffset, iSize);
nOffset += iSize;
rtp_send_data(buf, iSize + 2, mark, timestamp);
}
}
else {
rtp_send_data(data, dlen, true, timestamp);
}
}
h265
h265 稍微简单一些
void send_rtp_h265(uint8_t *buf, int len, int last_packet_of_frame,uint32_t ts)
{
int rtp_payload_size = max_payload_size - RTP_HEVC_HEADERS_SIZE;
int nal_type = (buf[0] >> 1) & 0x3F;
if (len <= max_payload_size)
{
rtp_send_data(buf, len, 0, ts);
}
else
{
buf[0] = 49 << 1;
buf[1] = 1;
buf[2] = nal_type;
buf[2] |= 1 << 7;
buf += 2;
len -= 2;
while (len > rtp_payload_size)
{
memcpy(&buf[RTP_HEVC_HEADERS_SIZE], buf, rtp_payload_size);
rtp_send_data(buf, max_payload_size, 0,ts);
buf += rtp_payload_size;
len -= rtp_payload_size;
buf[2] &= ~(1 << 7);
}
buf[2] |= 1 << 6;
memcpy(&buf[RTP_HEVC_HEADERS_SIZE], buf, len);
rtp_send_data(buf, len + 2, last_packet_of_frame,ts);
}
}
其他方式
这里建议的其他方式为使用ffmpeg,事实上ffmpeg封装了各类编码格式的rtp,可以直接调用,不详细解释,可以直接使用以下代码,当然,需要变格式时请自行改变
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
}
class RTP_Wrapper
{
AVFormatContext * m_fmtctx = NULL;
AVStream * m_st_v = NULL;
AVStream * m_st_a = NULL;
AVCodecContext *m_p_v = NULL;
AVCodecContext *m_p_a = NULL;
public:
int init_rtp(AVCodecContext *v, AVCodecContext *a,const char * url, unsigned short port)
{
int ret = -1;
m_p_v = v;
m_p_a = a;
AVOutputFormat* fmt = av_guess_format("rtp", NULL, NULL);
char rtp[128];
sprintf(rtp, "%s:%d", url, port);
ret = avformat_alloc_output_context2(&m_fmtctx, fmt, fmt->name,
rtp);
AVDictionary *options = NULL;
av_dict_set(&options, "buffer_size", "102400", 0);
av_dict_set(&options, "send_buffer_size", "102400", 0);
avio_open(&m_fmtctx->pb, rtp, AVIO_FLAG_WRITE);
if (v != NULL)
{
AVCodec *cv = avcodec_find_encoder(AV_CODEC_ID_H264);
m_st_v = avformat_new_stream(m_fmtctx, cv);
avcodec_parameters_from_context(m_st_v->codecpar, v);
}
if (a != NULL)
{
AVCodec *ca = avcodec_find_encoder(AV_CODEC_ID_AAC);
m_st_a = avformat_new_stream(m_fmtctx, ca);
avcodec_parameters_from_context(m_st_a->codecpar, a);
}
#if 0
char buffer[128];
sprintf(buffer, "rtp://%s:%d", "127.0.0.1", 6666);
m_fmtctx->oformat = av_guess_format("rtp", buffer, NULL);
if (avio_open(&m_fmtctx->pb, buffer, AVIO_FLAG_WRITE) < 0)
return -1;
#endif
avformat_write_header(m_fmtctx, NULL);
char sdp[256];
av_sdp_create(&m_fmtctx, 1, sdp, sizeof(sdp));
FILE * fp = fopen("c:\\test.sdp", "wb");
fwrite(sdp, 1, strlen(sdp), fp);
fclose(fp);
printf("%s\n", sdp);
return 0;
}
void send(AVPacket * pkt)
{
pkt->stream_index = m_st_v->index;
pkt->pts = av_rescale_q(pkt->pts, m_p_v->time_base,m_st_v->time_base);
pkt->dts = av_rescale_q(pkt->dts, m_p_v->time_base, m_st_v->time_base);
pkt->pos = -1;
av_interleaved_write_frame(m_fmtctx, pkt);
av_packet_free(&pkt);
}
void UnInit()
{
if (!(m_fmtctx->oformat->flags & AVFMT_NOFILE))
avio_close(m_fmtctx->pb);
avformat_free_context(m_fmtctx);
}
};
|