系列文章目录
前言
一、bit位写数据?
在通信行业或者音视频行业,通常数据格式是以bit来计算的,不同位置的bit位代表着不同的含义。因此bit为数据的写入对于c++开发尤为重要,本文将介绍一种实现的demo,来写rtp数据,rtp包格式如下:
V : 2bits,表示版本号
P : 1bit,表示是否支持填充,置为1的时候,表示在packet的末尾进行填充,方便一些针对固定长度算法的封装
X : 1bit, 表示是否支持Rtp头扩展,置为1的时候,RtpHeader以后会跟1个header extension
CC (CSRC count): 4bits,表示头部以后contributing sources identifiers的个数
M : 1bit;对于视频,标记一帧的结束;对于音频,标记会话的开始
PT : 7bits,表示传输的多媒体类型,(https://tools.ietf.org/html/rfc3551)
sequence number :16bits(2字节),表示RTP包序号
timestamp :32bits(4字节),表示时间戳, 必须使用90 kHz 时钟频率
SSRC :32bits(4字节),用于标识同步信源,参加同一视频会议的两个同步信源不能有相同的SSRC
CSRC :特约信源标识符,每一个CSRC占用4个字节,能够有0~15个。每一个CSRC标识了包含在该RTP报文有效载荷中的全部特约信源。
二、使用步骤
1.bit函数的实现
bits.h实现
#include <malloc.h>
#include <cstdint>
struct bits_buffer_t
{
int i_size;
int i_data;
uint8_t i_mask;
uint8_t *p_data;
};
typedef struct bits_buffer_t bits_buffer_t;
// 小端存储 低字节存低地址
// 10=0x0A --->内存中存储格式 0110 0000
static void bits_write(struct bits_buffer_t *p_buffer, int bit_count, uint64_t i_bits)
{
while (bit_count> 0){
bit_count--;
if ((i_bits >> bit_count) & 0x01){
p_buffer->p_data[p_buffer->i_data] |= p_buffer->i_mask; // 1
}
else{
p_buffer->p_data[p_buffer->i_data] &= ~p_buffer->i_mask;// 0
}
//move right one bit from left to right
p_buffer->i_mask >>= 1;
//means one byte is over,then restart from begin
if (p_buffer->i_mask == 0){
p_buffer->i_data++;
p_buffer->i_mask = 0x80;
}
}
}
2.rtp组包函数的实现
rtp实现
#include "bits.h"
#define RTP_HDR_LEN 12
/**
* RTP头封装
* @param pData buffer地址
* @param seqNum 序号
* @param timestamp 时间戳
* @param ssrc 标识
* @return
*/
int gb28181_make_rtp_header(char *pData, int seqNum, int64_t timestamp, int ssrc, int isEnd)
{
bits_buffer_t bitsBuffer;
bitsBuffer.i_size = RTP_HDR_LEN;
bitsBuffer.i_data = 0;
bitsBuffer.i_mask = 0x80;
bitsBuffer.p_data = (unsigned char *)(pData);
memset(bitsBuffer.p_data, 0, RTP_HDR_LEN);
bits_write(&bitsBuffer, 2, 2); /*协议版本*/
bits_write(&bitsBuffer, 1, 0); /*P*/
bits_write(&bitsBuffer, 1, 0); /*X*/
bits_write(&bitsBuffer, 4, 0); /*CSRC个数*/
bits_write(&bitsBuffer, 1, isEnd); /*一帧是否结束*/
bits_write(&bitsBuffer, 7, 96); /*载荷的数据类型*/
bits_write(&bitsBuffer, 16, seqNum); /*序列号,第几个*/
bits_write(&bitsBuffer, 32, timestamp); /*时间戳,第一个 */
bits_write(&bitsBuffer, 32, ssrc); /*同步信源(SSRC)标识符*/
return 0;
}
rtp header长度为12字节:
2+1+1+4 + 1+7 + 16 + 32 +32 = 12bytes
一次发送rtp包
char rtp_header[RTP_HDR_LEN];
int rtp_length = 3000;
int single_packet_max_length = 1400;
int rtp_seq = 0;
int time_base = 90000;
int fps = 25;
int send_packet_interval = 1000 / fps;
int interval = time_base / fps;
int ssrc = 0xffffffff;
long pts = 0;
int rtp_packet_count = ((rtp_length - 1) / single_packet_max_length) + 1;
int single_packet_max_length = 1400;
for (int i = 0; i < rtp_packet_count; i++) {
gb28181_make_rtp_header(rtp_header, rtp_seq, pts, ssrc, i ==(rtp_packet_count - 1));
rtp_seq++;
//udp send
//udp->send_packet
}
pts += interval;
std::this_thread::sleep_for(std::chrono::milliseconds(send_packet_interval ));
总结
通过以上例子,应该对bit的操作有了一定的理解,希望你能够从中受益。
本文含有隐藏内容,请 开通VIP 后查看