/// <summary>
/// RTP数据包类
/// </summary>
public class RTPPacket
{
/// <summary>
/// 获取数据包头信息V
/// </summary>
public int V
{
get;
private set;
}
/// <summary>
/// 获取数据包头信息P
/// </summary>
public bool P
{
get;
private set;
}
/// <summary>
/// 获取数据包头信息X
/// </summary>
public bool X
{
get;
private set;
}
/// <summary>
/// 获取数据包头信息CC
/// </summary>
public int CC
{
get;
private set;
}
/// <summary>
/// 获取数据包头信息M
/// </summary>
public bool M
{
get;
private set;
}
/// <summary>
/// 获取数据包头信息PT
/// </summary>
public int PT
{
get;
private set;
}
/// <summary>
/// 获取数据包头信息SequenceNumber
/// </summary>
public ushort SequenceNumber
{
get;
private set;
}
/// <summary>
/// 获取数据包头信息Timestamp
/// </summary>
public uint Timestamp
{
get;
private set;
}
/// <summary>
/// 获取数据包头信息SSRC
/// </summary>
public uint SSRC
{
get;
private set;
}
/// <summary>
/// 获取数据包头信息CSRC
/// </summary>
public List<uint> CSRC
{
get;
private set;
}
/// <summary>
/// 获取数据包有效数据
/// </summary>
public byte[] Payload
{
get;
private set;
}
/// <summary>
/// 获取数据包有效数据长度
/// </summary>
public uint PayloadSize
{
get;
private set;
}
/// <summary>
/// 获取数据包头信息长度
/// </summary>
public uint HeaderSize
{
get;
private set;
}
/// <summary>
/// 构造RTP数据包类
/// </summary>
/// <param name="buffer">RTP数据包数据</param>
public RTPPacket(byte[] buffer)
{
// 判断数据长度是否有效
if (buffer.LongLength > 12)
{
// 根据RTP数据包头信息解析数据
byte item = buffer[0];
V = item >> 6;
P = Convert.ToBoolean((item >> 5) & 1);
X = Convert.ToBoolean((item >> 4) & 1);
CC = item & 15;
item = buffer[1];
M = Convert.ToBoolean((item >> 7) & 1);
PT = item & 127;
SequenceNumber = ReadUInt16(buffer[2], buffer[3]);
Timestamp = ReadUInt32(buffer[4], buffer[5], buffer[6], buffer[7]);
SSRC = ReadUInt32(buffer[8], buffer[9], buffer[10], buffer[11]);
int index = 12;
CSRC = new List<uint>();
for (var i = 0; i < CC; i++)
{
index = i * 4 + index;
uint csrc = ReadUInt32(buffer[index], buffer[index + 1], buffer[index + 2], buffer[index + 3]);
CSRC.Add(csrc);
}
index = CC * 4 + index;
if (X)
{
index++;
index += buffer[index];
}
Payload = buffer.Skip(index).ToArray();
PayloadSize = (uint)Payload.LongLength;
HeaderSize = (uint)(CSRC.Count * 4 + 12);
}
}
/// <summary>
/// 构造RTP数据包类
/// </summary>
/// <param name="packet">RTP数据包</param>
public RTPPacket(RTPPacket packet)
{
// 复制RTP数据包成员
V = packet.V;
P = packet.P;
X = packet.X;
CC = packet.CC;
M = packet.M;
PT = packet.PT;
SequenceNumber = packet.SequenceNumber;
Timestamp = packet.Timestamp;
SSRC = packet.SSRC;
CSRC = packet.CSRC;
Payload = packet.Payload;
PayloadSize = packet.PayloadSize;
HeaderSize = packet.HeaderSize;
Debug.WriteLine(ToString());
}
/// <summary>
/// 根据四个字节读取UInt32数据
/// </summary>
/// <param name="byte1">字节1</param>
/// <param name="byte2">字节2</param>
/// <param name="byte3">字节3</param>
/// <param name="byte4">字节4</param>
/// <returns>返回UInt32数据</returns>
private uint ReadUInt32(byte byte1, byte byte2, byte byte3, byte byte4)
{
uint uint1 = (uint)(byte1 << 24);
uint uint2 = (uint)(byte2 << 16);
uint uint3 = (uint)(byte3 << 8);
uint uint4 = (uint)byte4;
return (uint)(((uint1 | uint2) | uint3) | uint4);
}
/// <summary>
/// 根据两个字节读取UInt16数据
/// </summary>
/// <param name="byte1">字节1</param>
/// <param name="byte2">字节2</param>
/// <returns>返回UInt16数据</returns>
private ushort ReadUInt16(byte byte1, byte byte2)
{
ushort ushort1 = (ushort)(byte1 << 8);
ushort ushort2 = (ushort)byte2;
return (ushort)(ushort1 | ushort2);
}
/// <summary>
/// 重载获取字符串方法
/// </summary>
/// <returns>返回RTP数据包对象的字符串表现形式</returns>
public override string ToString()
{
StringBuilder builder = new StringBuilder();
builder.Append(string.Format("V: {0}, ", V));
builder.Append(string.Format("P: {0}, ", P));
builder.Append(string.Format("X: {0}, ", X));
builder.Append(string.Format("CC: {0}, ", CC));
builder.Append(string.Format("M: {0}, ", M));
builder.Append(string.Format("PT: {0}, ", PT));
builder.Append(string.Format("SequenceNumber: {0}, ", SequenceNumber));
builder.Append(string.Format("Timestamp: {0}, ", Timestamp));
builder.Append(string.Format("SSRC: {0}, ", SSRC));
builder.Append(string.Format("CSRC: {0}, ", string.Join(" ", CSRC)));
builder.Append(string.Format("PayloadSize: {0};", PayloadSize));
return builder.ToString();
}
/// <summary>
/// 重载对象是否相同
/// </summary>
/// <param name="obj">要比较的对象</param>
/// <returns>返回对象是否相同</returns>
public override bool Equals(object obj)
{
RTPPacket packet = obj as RTPPacket;
if (packet == null)
{
return false;
}
else
{
return SequenceNumber == packet.SequenceNumber;
}
}
/// <summary>
/// 重载获取HashCode
/// </summary>
/// <returns>返回SequenceNumber</returns>
public override int GetHashCode()
{
return SequenceNumber;
}
/// <summary>
/// ==运算符重载
/// </summary>
/// <param name="packet1">左边RTP数据包对象</param>
/// <param name="packet2">右边RTP数据包对象</param>
/// <returns>返回是否相等</returns>
public static bool operator ==(RTPPacket packet1, RTPPacket packet2)
{
if (ReferenceEquals(packet1, packet2))
{
return true;
}
else if (ReferenceEquals(packet1, null) || ReferenceEquals(packet2, null))
{
return false;
}
else
{
return packet1.Equals(packet2);
}
}
/// <summary>
/// !=运算符重载
/// </summary>
/// <param name="packet1">左边RTP数据包对象</param>
/// <param name="packet2">右边RTP数据包对象</param>
/// <returns>返回是否不相等</returns>
public static bool operator !=(RTPPacket packet1, RTPPacket packet2)
{
return !(packet1 == packet2);
}
}
标签: C#
C#开发指南
关于C#中重置URL参数的说明
/// <summary>
/// 构造URL参数信息
/// </summary>
/// <param name="includeEmpty">是否包括空值参数</param>
/// <param name="nameValues">要构造的URL参数信息,由键值对构成,如name=value</param>
/// <returns>返回构造后URL参数信息</returns>
public virtual Dictionary<string, List<object>> BuildUrlParams(bool includeEmpty, params object[] nameValues)
{
// 定义新的URL参数字典
Dictionary<string, List<object>> newParams = new Dictionary<string, List<object>>();
// 构造要设置的URL参数信息
string nameValue = string.Join("&", nameValues);
// 拆分URL参数信息
string[] oldParams = nameValue.Split(new string[] { "&" }, StringSplitOptions.RemoveEmptyEntries);
// 遍历每个URL参数
for (int i = 0, length = oldParams.Length; i < length; i++)
{
// 获取URL参数的键值对
string[] items = oldParams[i].Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries);
// 判断URL参数的键值对是否有效
if (items.Length > 0)
{
// 获取参数名
string name = items[0];
// 获取参数值
string value = null;
if (items.Length > 1)
{
value = items[1];
}
// 判断URL参数的键值对是否有效
if (includeEmpty || value != null)
{
// 获取已构造的参数值
List<object> values;
if (!newParams.TryGetValue(name, out values))
{
// 没有构造过参数则添加新的参数信息
values = newParams[name] = new List<object>();
}
// 添加新的参数值
if (value != null)
{
// 如参数未URL编码则对其进行编码
value = HttpUtility.UrlDecode(value, Encoding) == value ? HttpUtility.UrlEncode(value, Encoding) : value;
values.Add(value);
}
}
}
}
// 返回构造后URL参数信息
return newParams;
}
/// <summary>
/// 设置URL参数
/// </summary>
/// <param name="url">要设置参数的URL</param>
/// <param name="nameValues">要设置的参数信息,由键值对构成,如name=value</param>
/// <returns>返回设置参数后的URL</returns>
public virtual string SetUrlParams(string url, params object[] nameValues)
{
// 构造要设置的URL参数信息
Dictionary<string, List<object>> newParams = BuildUrlParams(true, nameValues);
// 获取URL地址中参数开始索引
int index = url.IndexOf("?");
// 判断URL地址中是否有参数
if (index >= 0)
{
// 构造原始的URL参数信息
Dictionary<string, List<object>> oldParams = BuildUrlParams(false, url.Substring(index + "?".Length));
// 获取不带参数的URL地址
url = url.Substring(0, index);
// 判断是否存在原始URL参数信息
if (oldParams.Count > 0)
{
// 遍历要设置的URL参数信息
foreach (KeyValuePair<string, List<object>> item in newParams)
{
// 将要设置的URL参数信息覆盖添加到原始参数信息中
oldParams[item.Key] = item.Value;
}
// 重新设置URL参数信息
newParams = oldParams;
}
}
// 判断是否有参数
if (newParams.Count > 0)
{
// 构造新的URL参数信息
string newParam = string.Join("&", newParams.Where(n => n.Value.Count > 0).Select(n => string.Format("{0}={1}", n.Key, string.Join(",", n.Value))));
// 返回构造后的URL地址
return string.Format("{0}?{1}", url, newParam);
}
else
{
// 没有参数则返回不带参数的URL地址
return url;
}
}
关于C#中按位处理枚举的说明
一、定义:
在枚举上添加[Flags]属性,并以2的幂定义枚举的各个值:
[Flags]
public enum TestEnum
{
Value0 = 1,
Value1 = 2,
Value2 = 4,
Value3 = 8,
Value4 = 16,
All = Value0 | Value1 | Value2 | Value3 | Value4
}
二、比较:
按位运算比较枚举值是否包括某个值:
// 定义枚举变量 TestEnum testEnum = TestEnum.Value1 | TestEnum.Value2; // 判断枚举变量是否包含枚举Value2的值 bool hasValue = ((testEnum & TestEnum.Value2) == TestEnum.Value2); // 返回判断结果 return hasValue;
更多信息请参阅:FlagsAttribute 类 (System)
关于C#中设置URL参数的说明
/// <summary>
/// 设置URL参数
/// </summary>
/// <param name="url">要设置参数的URL</param>
/// <param name="name">参数名</param>
/// <param name="value">参数值</param>
/// <returns>返回设置参数后的URL</returns>
public string SetUrlParam(string url, string name, object value)
{
// 获取URL地址中参数开始索引
int index = url.IndexOf("?");
// 判断URL地址中是否有参数
if (index >= 0)
{
// 获取不带参数的URL地址
string baseUrl = url.Substring(0, index);
// 获取URL地址中的参数信息
string paramUrl = url.Substring(index);
// 判断要设置的参数是否是第一个参数
if (paramUrl.StartsWith("?" + name + "="))
{
// 获取要设置的参数后面的参数开始的索引
index = paramUrl.IndexOf("&");
// 判断后面是否有参数
if (index >= 0)
{
// 有参数则构造新的URL地址
return string.Format("{0}?{1}={2}{3}", baseUrl, name, value, paramUrl.Substring(index));
}
else
{
// 没参数则构造新的URL地址
return string.Format("{0}?{1}={2}", baseUrl, name, value);
}
}
else
{
// 不是第一个参数则获取要设置参数的索引位置
index = paramUrl.IndexOf("&" + name + "=");
// 判断是否存在要设置的参数
if (index >= 0)
{
// 获取要设置参数的前面的参数
string temp1 = paramUrl.Substring(0, index);
// 获取要设置参数的后面的参数
string temp2 = paramUrl.Substring(index + ("&" + name + "=").Length);
// 获取要设置的参数后面的参数开始的索引
index = temp2.IndexOf("&");
// 判断后面是否有参数
if (index >= 0)
{
// 有参数则构造新的URL地址
return string.Format("{0}{1}&{2}={3}{4}", baseUrl, temp1, name, value, temp2.Substring(index));
}
else
{
// 没参数则构造新的URL地址
return string.Format("{0}{1}&{2}={3}", baseUrl, temp1, name, value);
}
}
else
{
// 不存在参数则构造新的URL地址
return string.Format("{0}&{1}={2}", url, name, value);
}
}
}
else
{
// 原URL地址中没参数则直接构成新的URL地址
return string.Format("{0}?{1}={2}", url, name, value);
}
}
关于C#中控制鼠标位置的说明
// 定义设置鼠标位置的Windows API函数
[DllImport("user32.dll")]
private static extern int SetCursorPos(int x, int y);
// 获取鼠标当前X坐标
int x = Control.MousePosition.X;
// 获取鼠标当前Y坐标
int y = Control.MousePosition.Y;
// 设置新的鼠标位置
SetCursorPos(x + 1, y - 1);