2011-12-07 15:33:50 iteye_2638 阅读数 12
  • 视频编解码之HEVC视频教程

    本课程主要介绍视频编解码的基础知识,并详细讲解新一代视频编解码标准HEVC。涉及到的课程内容有:数字视频格式、HEVC编码结构、帧间帧内预测、残差变换、残差变换系数量化、环路后处理、熵编码等。

    3636 人正在学习 去看看 梅奥
Android短信编码在Framework层实现。

对于普通短信,其SmsHeader部分为空。

Gsm:

Gsm中,对于长短信,使用了SmsHeader类进行描述。SmsHeader.ConcatRef描述了长短信的refNumber(对于同一个短信,相同,使用SmsDispatcher.getNextConcatenatedRef方法获取一个索引值,将其或上0x00FF),seqNumber(分段序列号,从1开始),msgCount(分段数量)。然后设置isEightBits为假(为了支持不同长度REFERENCE的短信,8位则REFERENCE为8位,否则为16位)。

短信头的编码位于SmsHeader.toByteArray中。

1?????????? 写入concatRef

1.1????????? 若为8位REFERENCE,写入ELT_ID_CONCATENATED_8_BIT_REFERENCE(00000000),写入剩下concatRef的字节数(此处设为00000011,表示3个字节),写入refNumber(低8位)

1.2????????? 若为16位,写入ELT_ID_CONCATENATED_16_BIT_REFERENCE(00001000),写入剩下concatRef的字节数(此处设为00000100,表示4个字节),写入refNumber(先写入高8位,再写入低8位)

1.3????????? 写入msgCount(低8位)与seqNumber(低8位)

2?????????? 写入PortAddrs

3?????????? 写入specialSmsMsgList

4?????????? 写入miscEltList

短信内容编码从Gsm的SmsMessage.getSubmitPdu方法开始(com.android.internal.telephony.gsm.SmsMessage)

1?????????? 设置MTIBYTE(TP-Message-Type-Indicator,初始为00000001)与UDHI。若SmsHeader不为空,MTIBYTE为01000001,否则为00000001

2?????????? 调用Gsm的SmsMessage.getSubmitPduHeader写入基本信息,返回一个ByteArrayOutputStream

1??????????

2??????????

2.1????????? 设置SubmitPdu的服务中心地址

2.2????????? 若需要接收报告,MTIBYTE|=00100000。(TP-Status-Report-Request)

2.3????????? 将MTIBYTE写入输出流(低8位)

2.4????????? 写入一个字节00000000(TP-Message-Reference)

2.5????????? 写入目标号码长度(有效数字个数,如号码12345为5)(低8位)

2.6????????? 写入目标号码(第一个字节为TOA,号码中有加号则为10010001,表示国际号码,否则为10000001未知,TS 24.008 10.5.4.7。后面为BCD码字节数组,每个字节存两个数,不存加号,顺序是反的。如13 24 58表示号码31 42 85。如果号码长度是奇数,最后一个字节的高4位为1111,如13 22 F5表示号码31 22 5)

2.7????????? 写入一个字节00000000(TP-Protocol-Identifier)

3?????????? 若编码方式未指定,默认使用7BIT

4?????????? 如果使用7BIT编码,调用GsmAlphabet.stringToGsm7BitPacketedWithHeader进行编码,获取编码后的字节数组

4.1????????? 如果没有Header,直接调用GsmAlphabet.stringToGsm7BitPacket获取编码后的数据字节数组(startingSeptetOffset=0)

4.1.1???? 调用GsmAlphabet.countGsmSeptets计算7BIT编码所需的字节数(计算结果要加上头部的7BIT编码所需的字节数)

4.1.2???? 若超过255个字节,抛出异常

4.1.3???? 计算使用字节数组保存编码后的7BIT数据所需的字节数(包括Header)

4.1.4???? 将数据以7BIT编码的方式写入字节数组

4.1.5???? 在数组的0号位写入7BIT编码所需的字节数(包括Header),返回

4.2????????? 否则,先计算Header的7BIT编码后的长度(包括表示头长度的字节),调用GsmAlphabet.stringToGsm7BitPacket获取编码后的数据字节数组(startingSeptetOffset=Header的长度),在编码后的数据字节数组前面预留出该长度的部分(同4.1.1-4.1.5)。在1号位写入头的长度,其后为Header的内容(Header未进行7BIT编码,但为什么后面的空间是按7BIT空出来?)

4.3????????? 若所需字节数未超过MAX_USER_DATA_SEPTETS,往输出流中写入一个字节00000000(TP-Data-Coding-Scheme,默认编码,未压缩)

5?????????? 否则使用UCS-2方式,调用Gsm的SmsMessage.encodeUCS2进行编码,获取编码后的字节数组

5.1????????? 将消息正文转成utf-16be格式

5.2????????? 若包含Header,则创建一个新字节数组用于存放待输出数据,0号位存放Header长度,后面接着Header和转换后的正文。否则,仅输出转换后的消息正文

5.3????????? 创建一个新的字节数组,长度比待输出数据多一。0号位存放待输出数据长度,后面跟着待输出数据

5.4????????? 若所需字节数未超过MAX_USER_DATA_BYTES,往输出流中写入一个字节00001011(TP-Data-Coding-Scheme,Class 3,UCS-2,未压缩)

6?????????? 往输出流中写入编码后的字节数组

Gsm短信发送(SMS-SUBMIT)编码格式(不全,具体参见GSM短信标准中9.2.2.2 SMS SUBMIT type)如下图所示:

<br><img src="http://dl.iteye.com/upload/attachment/598604/ecc68d21-d821-368f-9a65-d5ac5a868c1c.jpg" alt=""><br>?

用户数据区域如下图所示,UDL-用户数据长度,UDHL-用户数据头长度,UDH-用户数据头。若没有Header,则只包括TP-UDL和编码后的短信内容(由TP-UDHI标识)。

<br><img src="http://dl.iteye.com/upload/attachment/598606/47c41b70-b49d-31d6-ad37-c6916f11a1de.jpg" alt=""><br>?<br>对于Gsm,还要在RIL中,将smscPdu与内容pdu进行整合。smscPdu的格式与内容pdu类似,先是一个长度字节(后面号码内容的长度),后面是号码的BCD编码(格式与目标号码相同,也包括TOA)。

Gsm其它类型的PDU可参考标准中的说明,大致结构都差不多。总共包括以下六种。其中,SMS-DELIVER的解码在RIL的processUnsolicited的RIL_UNSOL_RESPONSE_NEW_SMS中调用。

1.???????? SMS-DELIVER,包含从SC到MS的消息(手机收到的短信)。

2.???????? SMS-DELIVER-REPORT,包含

a)?????? 失败原因(如果需要的话)

b)????? 对于SMS-DELIVER或SMS-STATUSREPORT的确认

3.???????? SMS-SUBMIT,包含从MS到SC的消息(从手机发出的短信)。

4.???????? SMS-SUBMIT-REPORT,包含

a)?????? 失败原因(如果需要的话)

b)????? 对于SMS-SUBMIT或SMS-COMMAND的确认

5.???????? SMS-STATUS-REPORT,包含从SC到MS的状态报告。

6.???????? SMS-COMMAND,包含从MS到SC的命令。

?

Cdma:

Cdma的SmsHeader的内容与Gsm几乎没有区别,只是isEightBits为真。

Cdma使用了UserData来辅助构造SubmitPdu,其中的payloadStr存储了不同分段的短信字符串,userDataHeader存储了SmsHeader,msgEncoding存储了编码类型,msgEncodingSet用于指明是否指明编码类型(此处设为真)。

对于普通短信,其userDataHeader为空,msgEncoding与msgEncodingSet均未设置。剩下的编码过程与长短信相同。

Cdma的长短信内容编码也是从Cdma的SmsMessage.getSubmitPdu方法开始,最后转到Cdma的SmsMessage.privateGetSubmitPdu方法进行编码。(com.android.internal.telephony.cdma.SmsMessage)

1?????????? 利用目标地址构造一个CdmaSmsAddress

2?????????? 构造BearerData对象用于辅助编码,其中消息类型messageType设为BearerData.MESSAGE_TYPE_SUBMIT(0x02),获取了一个MessageId(自增,C.S0015-B,v2.0,4.3.1.5),deliveryAckReq为是否需要接收报告,userAckReq、readAckReq、reportReq均为假,userData为UserData对象。

3?????????? 使用BearerData.encode方法对BearerData对象进行编码,获得一个字节数组(3GPP2,C.R1001-F,v1.0,4.5)。其格式为SUBPARAMETER_ID后面带上相应的数据。

3.1????????? 构造一个BitwiseOutputStream进行数据的编码,该输出流能够往其中写入任意位数的数据,而不限于字节的边界

3.2????????? 往输出流中写入SUBPARAM_MESSAGE_IDENTIFIER(0x00)(3GPP2 C.S0015-B,v2.0表4.5-1),8位

3.3????????? 往输出流中写入MessageId(3GPP2 C.S0015-B,4.5.1 Message Identifier)

3.3.1???? 写入00000011,8位

3.3.2???? 写入消息类型,4位

3.3.3???? 写入MessageId的高8位

3.3.4???? 写入MessageId的低8位

3.3.5???? 写入是否有用户数据头,1有,0无,1位

3.3.6???? 跳过3位(留作备用)

3.4????????? 若userData不空,输出(3GPP2 C.S0015-B,4.5.2 User Data)

3.4.1???? 写入SUBPARAM_USER_DATA(0x01),8位

3.4.2???? 对UserData的payload使用Bearer.encodeUserDataPayload进行编码

3.4.2.1??? 若payloadStr为空且msgEncoding不是ENCODING_OCTET(3GPP2 C.R1001-F,v1.0,表9.1-1),设payloadStr为空串

3.4.2.2??? 若userDataHeader不空,编码并返回

3.4.2.2.1?? 使用SmsHeader的toByteArray方法将SmsHeader编码为字节数组(具体过程前面介绍了)

3.4.2.2.2?? 根据编码类型msgEncoding的不同,分别调用不同方法,将SmsHeader数组编码成不同的字节数组。若没指定字符集,默认使用7BIT_ALPHABET。若出现异常,再使用UNICODE16。

3.4.2.2.2.1?????? 如果是ENCODING_GSM_7BIT_ALPHABET,调用BearerData.encode7bitEms,同Gsm的4.2,将编码后的字节数组存入UserData的payload,格式同Gsm的用户数据区域(去掉了第一个字节,即UDL)。将整个用户数据区域的长度存入UserData的numFields。

3.4.2.2.2.2?????? 如果是ENCODING_UNICODE_16,调用BearerData.encode16bitEms,将payloadStr编码为Utf-16be字节数组。将头的长度存入payload的0号字节,后面加上头的字节数组。如果前面的字节数为奇数,还要补上一个字节作为udhPadding以保证字节边界对齐。然后接上编码后的payloadStr。此处的numFields存的是16位单元的长度,即payload字节数除2。

3.4.2.2.2.3?????? 如果是ENCODING_7BIT_ASCII,调用BearerData.encode7bitEmsAscii,过程与ENCODING_GSM_7BIT_ALPHABET相同,只是字符集不同。

3.4.2.3??? 否则,说明为普通短信,没有Header。

3.4.2.3.1?? 如果设置了编码字符集,根据编码类型msgEncoding的不同设置相应的payload值。

3.4.2.3.1.1?????? 如果是ENCODING_OCTET。若 UserData.payload为空,payload设为一个空字节(00000000),numFields为0。若UserData.payload不空,numFields为payload的字节数。

3.4.2.3.1.2?????? 如果不是ENCODING_OCTET。若payloadStr为空,设其为空串。否则,根据编码字符集的不同,调用相应方法将payloadStr编码,具体方法同3.4.2.2.2,只是没有UDHL和UDH部分,只含编码后的短信内容。

3.4.2.3.2?? 若没有设置编码字符集,尝试使用7BIT_ASCII进行编码,若出现异常,再采用UNICODE_16。然后,将numFields设为payloadStr的长度(即字符个数)。

3.4.3???? 计算后面数据与参数的总字节数paramBytes(如果编码方式为ENCODING_IS91_EXTENDED_PROTOCOL或ENCODING_GSM_DCS,多加1字节),以及为了保证数据对齐所需的位数paddingBits

3.4.4???? 写入paramBytes,8位(SUBPARAM_LEN)

3.4.5???? 写入UserData的编码方式msgEncoding,5位

3.4.6???? 如果编码方式为ENCODING_IS91_EXTENDED_PROTOCOL或ENCODING_GSM_DCS,输出UserData的消息类型msgType,8位

3.4.7???? 写入UserData的numFields,8位

3.4.8???? 写入UserData的payload

3.4.9???? 如果需要补全,写入所需的空位paddingBits

3.5????????? 若callbackNumber不空,输出(目前未设置,3GPP2 C.S0015-B,v2,4.5.15)

3.6????????? 若userAckReq,deliveryAckReq,readAckReq,reportReq有一个为真,写入SUBPARAM_REPLY_OPTION(00001010),8位

3.6.1???? 写入00000001,8位

3.6.2???? 写入userAckReq,1位

3.6.3???? 写入deliveryAckReq,1位

3.6.4???? 写入readAckReq,1位

3.6.5???? 写入reportReq,1位

3.6.6???? 写入0000,4位

3.7????????? 若numberOfMessage不为0,输出(Voice Mail中的)

3.7.1???? 写入SUBPARAM_NUMBER_OF_MESSAGE(3GPP2 C.S0015-B,v2.0,4.5.12),8位

3.7.2???? 写入00000001,8位

3.7.3???? 写入BearerData的numberOfMessage,8位

3.8????????? 若validityPeriodRelativeSet为真,输出(目前未设置)——SUBPARAM_VALIDITY_PERIOD_RELATIVE

3.9????????? 若privacyIndicatorSet为真,输出(目前未设置)——SUBPARAM_PRIVACY_INDICATOR

3.10?????? 若languageIndicatorSet为真,输出(目前未设置)——SUBPARAM_LANGUAGE_INDICATOR

3.11?????? 若displayModeSet为真,输出(目前未设置)——SUBPARAM_MESSAGE_DISPLAY_MODE

3.12?????? 若priorityIndicatorSet为真,输出(目前未设置)——SUBPARAM_PRIORITY_INDICATOR

3.13?????? 若alertIndicator为真,输出(目前未设置)——SUBPARAM_ALERT_ON_MESSAGE_DELIVERY

3.14?????? 若messageStatusSet为真,输出(目前未设置)——SUBPARAM_MESSAGE_STATUS

4?????????? 若有SmsHeader,teleservice为SmsEnvelope.TELESERVICE_WEMT,否则为SmsEnvelope.TELESERVICE_WMT

5?????????? 构造一个ByteArrayOutputStream,使用DataOutputStream进行封装

6?????????? 往输出流中写入teleservice,Int

7?????????? 往输出流中写入0(Service Present),Int

8?????????? 往输出流中写入0(Service Category),Int

9?????????? 往输出流中写入digitMode(3GPP2,C.S0015-B,v2.0,3.4.3.3),byte

10??????? 往输出流中写入numberMode(3GPP2,C.S0015-B,v2.0,3.4.3.3),byte

11??????? 往输出流中写入ton,即numberType(TS 23.040 9.1.2.5,TS 24.008表10.5.118,C.S0005-D表2.7.1.3.2.4-2),byte

12??????? 往输出流中写入numberPlan(3GPP2,C.S0015-B,v2.0,3.4.3.3,C.S005-D表2.7.1.3.2.4-3),byte

13??????? 往输出流中写入地址长度numberOfDigits(3GPP2,C.S0015-B,v2.0,3.4.3.3),byte

14??????? 往输出流中写入CdmaSmsAddress中编码后的目标地址,byte[]

15??????? SubAddress不支持,故输出三个字节00000000

15.1?????? 往输出流中写入0(subaddressType),byte

15.2?????? 往输出流中写入0(subaddress_odd),byte

15.3?????? 往输出流中写入0(subaddress_nbr_of_digits),byte

16??????? 往输出流中写入编码后的BearerData字节数组的长度,byte

17??????? 往输出流中写入编码后的BearerData字节数组,byte[]

对于CDMA短信的解码,在RIL的processUnsolicited的RIL_UNSOL_RESPONSE_CDMA_NEW_SMS中调用,实际代码在com.android.internal.telephony.cdma.SmsMessage.newFromParcel中,解码格式与编码格式相同,只是存的地址变成了发出消息的手机的地址。




<ul style="display:none;">
[*][url=http://dl.iteye.com/upload/attachment/598604/ecc68d21-d821-368f-9a65-d5ac5a868c1c.jpg]<img src='http://dl.iteye.com/upload/attachment/598604/ecc68d21-d821-368f-9a65-d5ac5a868c1c-thumb.jpg' class='magplus' title='点击查看原始大小图片' />[/url]


[*]大小: 30.1 KB

</ul>



<ul style="display:none;">
[*][url=http://dl.iteye.com/upload/attachment/598606/47c41b70-b49d-31d6-ad37-c6916f11a1de.jpg]<img src='http://dl.iteye.com/upload/attachment/598606/47c41b70-b49d-31d6-ad37-c6916f11a1de-thumb.jpg' class='magplus' title='点击查看原始大小图片' />[/url]


[*]大小: 11.3 KB

</ul>



[list]
[*][url=#]查看图片附件[/url]

[/list]
2013-11-04 13:26:18 sonicliji 阅读数 885
  • 视频编解码之HEVC视频教程

    本课程主要介绍视频编解码的基础知识,并详细讲解新一代视频编解码标准HEVC。涉及到的课程内容有:数字视频格式、HEVC编码结构、帧间帧内预测、残差变换、残差变换系数量化、环路后处理、熵编码等。

    3636 人正在学习 去看看 梅奥
Android短信编解码方式

Android短信编码在Framework层实现。

对于普通短信,其SmsHeader部分为空。

Gsm:

Gsm中,对于长短信,使用了SmsHeader类进行描述。SmsHeader.ConcatRef描述了长短信的refNumber(对于同一个短信,相同,使用SmsDispatcher.getNextConcatenatedRef方法获取一个索引值,将其或上0x00FF),seqNumber(分段序列号,从1开始),msgCount(分段数量)。然后设置isEightBits为假(为了支持不同长度REFERENCE的短信,8位则REFERENCE为8位,否则为16位)。

短信头的编码位于SmsHeader.toByteArray中。

1           写入concatRef

1.1          若为8位REFERENCE,写入ELT_ID_CONCATENATED_8_BIT_REFERENCE(00000000),写入剩下concatRef的字节数(此处设为00000011,表示3个字节),写入refNumber(低8位)

1.2          若为16位,写入ELT_ID_CONCATENATED_16_BIT_REFERENCE(00001000),写入剩下concatRef的字节数(此处设为00000100,表示4个字节),写入refNumber(先写入高8位,再写入低8位)

1.3          写入msgCount(低8位)与seqNumber(低8位)

2           写入PortAddrs

3           写入specialSmsMsgList

4           写入miscEltList

短信内容编码从Gsm的SmsMessage.getSubmitPdu方法开始(com.android.internal.telephony.gsm.SmsMessage)

1           设置MTIBYTE(TP-Message-Type-Indicator,初始为00000001)与UDHI。若SmsHeader不为空,MTIBYTE为01000001,否则为00000001

2           调用Gsm的SmsMessage.getSubmitPduHeader写入基本信息,返回一个ByteArrayOutputStream

1          

2          

2.1          设置SubmitPdu的服务中心地址

2.2          若需要接收报告,MTIBYTE|=00100000。(TP-Status-Report-Request)

2.3          将MTIBYTE写入输出流(低8位)

2.4          写入一个字节00000000(TP-Message-Reference)

2.5          写入目标号码长度(有效数字个数,如号码12345为5)(低8位)

2.6          写入目标号码(第一个字节为TOA,号码中有加号则为10010001,表示国际号码,否则为10000001未知,TS 24.008 10.5.4.7。后面为BCD码字节数组,每个字节存两个数,不存加号,顺序是反的。如13 24 58表示号码31 42 85。如果号码长度是奇数,最后一个字节的高4位为1111,如13 22 F5表示号码31 22 5)

2.7          写入一个字节00000000(TP-Protocol-Identifier)

3           若编码方式未指定,默认使用7BIT

4           如果使用7BIT编码,调用GsmAlphabet.stringToGsm7BitPacketedWithHeader进行编码,获取编码后的字节数组

4.1          如果没有Header,直接调用GsmAlphabet.stringToGsm7BitPacket获取编码后的数据字节数组(startingSeptetOffset=0)

4.1.1     调用GsmAlphabet.countGsmSeptets计算7BIT编码所需的字节数(计算结果要加上头部的7BIT编码所需的字节数)

4.1.2     若超过255个字节,抛出异常

4.1.3     计算使用字节数组保存编码后的7BIT数据所需的字节数(包括Header)

4.1.4     将数据以7BIT编码的方式写入字节数组

4.1.5     在数组的0号位写入7BIT编码所需的字节数(包括Header),返回

4.2          否则,先计算Header的7BIT编码后的长度(包括表示头长度的字节),调用GsmAlphabet.stringToGsm7BitPacket获取编码后的数据字节数组(startingSeptetOffset=Header的长度),在编码后的数据字节数组前面预留出该长度的部分(同4.1.1-4.1.5)。在1号位写入头的长度,其后为Header的内容(Header未进行7BIT编码,但为什么后面的空间是按7BIT空出来?)

4.3          若所需字节数未超过MAX_USER_DATA_SEPTETS,往输出流中写入一个字节00000000(TP-Data-Coding-Scheme,默认编码,未压缩)

5           否则使用UCS-2方式,调用Gsm的SmsMessage.encodeUCS2进行编码,获取编码后的字节数组

5.1          将消息正文转成utf-16be格式

5.2          若包含Header,则创建一个新字节数组用于存放待输出数据,0号位存放Header长度,后面接着Header和转换后的正文。否则,仅输出转换后的消息正文

5.3          创建一个新的字节数组,长度比待输出数据多一。0号位存放待输出数据长度,后面跟着待输出数据

5.4          若所需字节数未超过MAX_USER_DATA_BYTES,往输出流中写入一个字节00001011(TP-Data-Coding-Scheme,Class 3,UCS-2,未压缩)

6           往输出流中写入编码后的字节数组

Gsm短信发送(SMS-SUBMIT)编码格式(不全,具体参见GSM短信标准中9.2.2.2 SMS SUBMIT type)如下图所示:



 

用户数据区域如下图所示,UDL-用户数据长度,UDHL-用户数据头长度,UDH-用户数据头。若没有Header,则只包括TP-UDL和编码后的短信内容(由TP-UDHI标识)。



 
对于Gsm,还要在RIL中,将smscPdu与内容pdu进行整合。smscPdu的格式与内容pdu类似,先是一个长度字节(后面号码内容的长度),后面是号码的BCD编码(格式与目标号码相同,也包括TOA)。

Gsm其它类型的PDU可参考标准中的说明,大致结构都差不多。总共包括以下六种。其中,SMS-DELIVER的解码在RIL的processUnsolicited的RIL_UNSOL_RESPONSE_NEW_SMS中调用。

1.         SMS-DELIVER,包含从SC到MS的消息(手机收到的短信)。

2.         SMS-DELIVER-REPORT,包含

a)       失败原因(如果需要的话)

b)      对于SMS-DELIVER或SMS-STATUSREPORT的确认

3.         SMS-SUBMIT,包含从MS到SC的消息(从手机发出的短信)。

4.         SMS-SUBMIT-REPORT,包含

a)       失败原因(如果需要的话)

b)      对于SMS-SUBMIT或SMS-COMMAND的确认

5.         SMS-STATUS-REPORT,包含从SC到MS的状态报告。

6.         SMS-COMMAND,包含从MS到SC的命令。

 

Cdma:

Cdma的SmsHeader的内容与Gsm几乎没有区别,只是isEightBits为真。

Cdma使用了UserData来辅助构造SubmitPdu,其中的payloadStr存储了不同分段的短信字符串,userDataHeader存储了SmsHeader,msgEncoding存储了编码类型,msgEncodingSet用于指明是否指明编码类型(此处设为真)。

对于普通短信,其userDataHeader为空,msgEncoding与msgEncodingSet均未设置。剩下的编码过程与长短信相同。

Cdma的长短信内容编码也是从Cdma的SmsMessage.getSubmitPdu方法开始,最后转到Cdma的SmsMessage.privateGetSubmitPdu方法进行编码。(com.android.internal.telephony.cdma.SmsMessage)

1           利用目标地址构造一个CdmaSmsAddress

2           构造BearerData对象用于辅助编码,其中消息类型messageType设为BearerData.MESSAGE_TYPE_SUBMIT(0x02),获取了一个MessageId(自增,C.S0015-B,v2.0,4.3.1.5),deliveryAckReq为是否需要接收报告,userAckReq、readAckReq、reportReq均为假,userData为UserData对象。

3           使用BearerData.encode方法对BearerData对象进行编码,获得一个字节数组(3GPP2,C.R1001-F,v1.0,4.5)。其格式为SUBPARAMETER_ID后面带上相应的数据。

3.1          构造一个BitwiseOutputStream进行数据的编码,该输出流能够往其中写入任意位数的数据,而不限于字节的边界

3.2          往输出流中写入SUBPARAM_MESSAGE_IDENTIFIER(0x00)(3GPP2 C.S0015-B,v2.0表4.5-1),8位

3.3          往输出流中写入MessageId(3GPP2 C.S0015-B,4.5.1 Message Identifier)

3.3.1     写入00000011,8位

3.3.2     写入消息类型,4位

3.3.3     写入MessageId的高8位

3.3.4     写入MessageId的低8位

3.3.5     写入是否有用户数据头,1有,0无,1位

3.3.6     跳过3位(留作备用)

3.4          若userData不空,输出(3GPP2 C.S0015-B,4.5.2 User Data)

3.4.1     写入SUBPARAM_USER_DATA(0x01),8位

3.4.2     对UserData的payload使用Bearer.encodeUserDataPayload进行编码

3.4.2.1    若payloadStr为空且msgEncoding不是ENCODING_OCTET(3GPP2 C.R1001-F,v1.0,表9.1-1),设payloadStr为空串

3.4.2.2    若userDataHeader不空,编码并返回

3.4.2.2.1   使用SmsHeader的toByteArray方法将SmsHeader编码为字节数组(具体过程前面介绍了)

3.4.2.2.2   根据编码类型msgEncoding的不同,分别调用不同方法,将SmsHeader数组编码成不同的字节数组。若没指定字符集,默认使用7BIT_ALPHABET。若出现异常,再使用UNICODE16。

3.4.2.2.2.1       如果是ENCODING_GSM_7BIT_ALPHABET,调用BearerData.encode7bitEms,同Gsm的4.2,将编码后的字节数组存入UserData的payload,格式同Gsm的用户数据区域(去掉了第一个字节,即UDL)。将整个用户数据区域的长度存入UserData的numFields。

3.4.2.2.2.2       如果是ENCODING_UNICODE_16,调用BearerData.encode16bitEms,将payloadStr编码为Utf-16be字节数组。将头的长度存入payload的0号字节,后面加上头的字节数组。如果前面的字节数为奇数,还要补上一个字节作为udhPadding以保证字节边界对齐。然后接上编码后的payloadStr。此处的numFields存的是16位单元的长度,即payload字节数除2。

3.4.2.2.2.3       如果是ENCODING_7BIT_ASCII,调用BearerData.encode7bitEmsAscii,过程与ENCODING_GSM_7BIT_ALPHABET相同,只是字符集不同。

3.4.2.3    否则,说明为普通短信,没有Header。

3.4.2.3.1   如果设置了编码字符集,根据编码类型msgEncoding的不同设置相应的payload值。

3.4.2.3.1.1       如果是ENCODING_OCTET。若 UserData.payload为空,payload设为一个空字节(00000000),numFields为0。若UserData.payload不空,numFields为payload的字节数。

3.4.2.3.1.2       如果不是ENCODING_OCTET。若payloadStr为空,设其为空串。否则,根据编码字符集的不同,调用相应方法将payloadStr编码,具体方法同3.4.2.2.2,只是没有UDHL和UDH部分,只含编码后的短信内容。

3.4.2.3.2   若没有设置编码字符集,尝试使用7BIT_ASCII进行编码,若出现异常,再采用UNICODE_16。然后,将numFields设为payloadStr的长度(即字符个数)。

3.4.3     计算后面数据与参数的总字节数paramBytes(如果编码方式为ENCODING_IS91_EXTENDED_PROTOCOL或ENCODING_GSM_DCS,多加1字节),以及为了保证数据对齐所需的位数paddingBits

3.4.4     写入paramBytes,8位(SUBPARAM_LEN)

3.4.5     写入UserData的编码方式msgEncoding,5位

3.4.6     如果编码方式为ENCODING_IS91_EXTENDED_PROTOCOL或ENCODING_GSM_DCS,输出UserData的消息类型msgType,8位

3.4.7     写入UserData的numFields,8位

3.4.8     写入UserData的payload

3.4.9     如果需要补全,写入所需的空位paddingBits

3.5          若callbackNumber不空,输出(目前未设置,3GPP2 C.S0015-B,v2,4.5.15)

3.6          若userAckReq,deliveryAckReq,readAckReq,reportReq有一个为真,写入SUBPARAM_REPLY_OPTION(00001010),8位

3.6.1     写入00000001,8位

3.6.2     写入userAckReq,1位

3.6.3     写入deliveryAckReq,1位

3.6.4     写入readAckReq,1位

3.6.5     写入reportReq,1位

3.6.6     写入0000,4位

3.7          若numberOfMessage不为0,输出(Voice Mail中的)

3.7.1     写入SUBPARAM_NUMBER_OF_MESSAGE(3GPP2 C.S0015-B,v2.0,4.5.12),8位

3.7.2     写入00000001,8位

3.7.3     写入BearerData的numberOfMessage,8位

3.8          若validityPeriodRelativeSet为真,输出(目前未设置)——SUBPARAM_VALIDITY_PERIOD_RELATIVE

3.9          若privacyIndicatorSet为真,输出(目前未设置)——SUBPARAM_PRIVACY_INDICATOR

3.10       若languageIndicatorSet为真,输出(目前未设置)——SUBPARAM_LANGUAGE_INDICATOR

3.11       若displayModeSet为真,输出(目前未设置)——SUBPARAM_MESSAGE_DISPLAY_MODE

3.12       若priorityIndicatorSet为真,输出(目前未设置)——SUBPARAM_PRIORITY_INDICATOR

3.13       若alertIndicator为真,输出(目前未设置)——SUBPARAM_ALERT_ON_MESSAGE_DELIVERY

3.14       若messageStatusSet为真,输出(目前未设置)——SUBPARAM_MESSAGE_STATUS

4           若有SmsHeader,teleservice为SmsEnvelope.TELESERVICE_WEMT,否则为SmsEnvelope.TELESERVICE_WMT

5           构造一个ByteArrayOutputStream,使用DataOutputStream进行封装

6           往输出流中写入teleservice,Int

7           往输出流中写入0(Service Present),Int

8           往输出流中写入0(Service Category),Int

9           往输出流中写入digitMode(3GPP2,C.S0015-B,v2.0,3.4.3.3),byte

10        往输出流中写入numberMode(3GPP2,C.S0015-B,v2.0,3.4.3.3),byte

11        往输出流中写入ton,即numberType(TS 23.040 9.1.2.5,TS 24.008表10.5.118,C.S0005-D表2.7.1.3.2.4-2),byte

12        往输出流中写入numberPlan(3GPP2,C.S0015-B,v2.0,3.4.3.3,C.S005-D表2.7.1.3.2.4-3),byte

13        往输出流中写入地址长度numberOfDigits(3GPP2,C.S0015-B,v2.0,3.4.3.3),byte

14        往输出流中写入CdmaSmsAddress中编码后的目标地址,byte[]

15        SubAddress不支持,故输出三个字节00000000

15.1       往输出流中写入0(subaddressType),byte

15.2       往输出流中写入0(subaddress_odd),byte

15.3       往输出流中写入0(subaddress_nbr_of_digits),byte

16        往输出流中写入编码后的BearerData字节数组的长度,byte

17        往输出流中写入编码后的BearerData字节数组,byte[]

对于CDMA短信的解码,在RIL的processUnsolicited的RIL_UNSOL_RESPONSE_CDMA_NEW_SMS中调用,实际代码在com.android.internal.telephony.cdma.SmsMessage.newFromParcel中,解码格式与编码格式相同,只是存的地址变成了发出消息的手机的地址。


2017-02-16 21:18:29 gocy123 阅读数 737
  • 视频编解码之HEVC视频教程

    本课程主要介绍视频编解码的基础知识,并详细讲解新一代视频编解码标准HEVC。涉及到的课程内容有:数字视频格式、HEVC编码结构、帧间帧内预测、残差变换、残差变换系数量化、环路后处理、熵编码等。

    3636 人正在学习 去看看 梅奥

PDU短信编解码格式说明(找来找去个人认为这一篇还是比较靠谱的)

5652人阅读 评论(1)收藏举报
分类:
共有三种方式来发送和接收SMS信息:Block Mode, Text Mode和PDU Mode。其中PDU Mode被所有手机支持,可以使用任何字符集,这也是手机默认的编码方式。

发送短消息常用Text和PDU(Protocol Data Unit,协议数据单元)模式。使用Text模式收发短信代码简单,实现起来十分容易,但最大的缺点是不能收发中文短信;而PDU模式不仅支持中文短信,也能发送英文短信。PDU模式收发短信可以使用3种编码:7-bit、8-bit和UCS2编码。7-bit编码用于发送普通的ASCII字符,它将一串7-bit的字符(最高位为0)编码成8-bit的数据,每8个字符可“压缩”成7个;8-bit编码通常用于发送数据消息,比如图片和铃声等;而UCS2编码用于发送Unicode字符。在这三种编码方式下,PDU串的用户信息(TP-UD)段最大容量(可以发送的短消息的最大字符数)分别是160、140和70。这里,将一个英文字母、一个汉字和一个数据字节都视为一个字符。
PDU串的用户信息长度(TP-UDL),在各种编码方式下意义有所不同。7-bit编码时,指原始短消息的字符个数,而不是编码后的字节数。8-bit编码时,就是字节数。UCS2编码时,也是字节数,等于原始短消息的字符数的两倍。如果用户信息(TP-UD)中存在一个头(基本参数的TP-UDHI为1),在所有编码方式下,用户信息长度(TP-UDL)都等于头长度与编码后字节数之和。如果采用GSM 03.42所建议的压缩算法(TP-DCS的高3位为001),则该长度也是压缩编码后字节数或头长度与压缩编码后字节数之和。 

PDU相当于一个数据包,它由构成消息(SMS)的信息组成。作为一种数据单元,它必须包含源/目的地址、保护(有效)时间、数据格式、协议类型和正文,正文长度可达140字节,它们都以十六进制表示。PDU结构根据短消息由移动终端发起或以移动终端为目的而不同。每条消息可以发送140个字节,由于本系统中最长的数据串没有超过140个字节,因此数据均可以用一条消息来发送。
一般的PDU编码由A B C D E F G H I J K L M十三项组成。
A:短信息中心地址长度,2位十六进制数(1字节)。
B:短信息中心号码类型,2位十六进制数。
C:短信息中心号码,B+C的长度将由A中的数据决定。
D:文件头字节,2位十六进制数。 
E:信息类型,2位十六进制数。
F:被叫号码长度,2位十六进制数。
G:被叫号码类型,2位十六进制数,取值同B。
H:被叫号码,长度由F中的数据决定。
I:协议标识,2位十六进制数。
J:数据编码方案,2位十六进制数。
K:有效期,2位十六进制数。
L:用户数据长度,2位十六进制数。
M:用户数据,其长度由L中的数据决定。J中设定采用UCS2编码,这里是中英文的Unicode字符。
PDU编码协议简单说明
例1 发送:SMSC号码是+8613800250500,对方号码是13693092030,消息内容是“Hello!”。从手机发出的PDU串可以是
08 91 68 31 08 20 05 05 F0 11 00 0D 91 68 31 96 03 29 30 F0 00 00 00 06 C8 32 9B FD 0E 01
对照规范,具体分析:
分段 含义 说明
08 SMSC地址信息的长度 共8个八位字节(包括91)
91 SMSC地址格式(TON/NPI) 用国际格式号码(在前面加‘+’)
68 31 08 20 05 05 F0 SMSC地址 8613800250500,补‘F’凑成偶数个
11 基本参数(TP-MTI/VFP) 发送,TP-VP用相对格式
00 消息基准值(TP-MR) 0
0D 目标地址数字个数 共13个十进制数(不包括91和‘F’)
91 目标地址格式(TON/NPI) 用国际格式号码(在前面加‘+’)
68 31 96 03 29 30 F0 目标地址(TP-DA) 8613693092030,补‘F’凑成偶数个
00 协议标识(TP-PID) 是普通GSM类型,点到点方式
00 用户信息编码方式(TP-DCS) 7-bit编码
00 有效期(TP-VP) 5分钟
06 用户信息长度(TP-UDL) 实际长度6个字节
C8 32 9B FD 0E 01 用户信息(TP-UD) “Hello!”
例2 接收:SMSC号码是+8613800250500,对方号码是13693092030,消息内容是“你好!”。手机接收到的PDU串可以是
08 91 68 31 08 20 05 05 F0 84 0D 91 68 31 96 03 29 30 F0 00 08 30 30 21 80 63 54 80 06 4F 60 59 7D 00 21
对照规范,具体分析:
分段 含义 说明
08 地址信息的长度 个八位字节(包括91)
91 SMSC地址格式(TON/NPI) 用国际格式号码(在前面加‘+’)
68 31 08 20 05 05 F0 SMSC地址 8613800250500,补‘F’凑成偶数个
84 基本参数(TP-MTI/MMS/RP) 接收,无更多消息,有回复地址
0D 回复地址数字个数 共13个十进制数(不包括91和‘F’)
91 回复地址格式(TON/NPI) 用国际格式号码(在前面加‘+’)
68 31 96 03 29 30 F0 回复地址(TP-RA) 8613693092030,补‘F’凑成偶数个
00 协议标识(TP-PID) 是普通GSM类型,点到点方式
08 用户信息编码方式(TP-DCS) UCS2编码
30 30 21 80 63 54 80 时间戳(TP-SCTS) 2003-3-12 08:36:45  +8时区
06 用户信息长度(TP-UDL) 实际长度6个字节
4F 60 59 7D 00 21 用户信息(TP-UD) “你好!”

详细解析:
 0891683108200505F011190D91683105155694F50008FF10008FF044F60597D
   <1>短信中心地址字段:0891 
    08:Address-Lengt(地址长度),短信息中心地址长度为8个字节,是(91)+(683108200505F0)的长度,8个8位字节
 91地址类型:10010001       Bit7:1。始终为1       Bits 6,5,4:Type-of-Number(号码类型):001,代表Internation Number。也即是号码前加“+”。注意:对某些比较特殊的号码,例如手机与小灵通的互通时,这里不能设置为001,而要设置成000,代表号码前没有“+”,否则无法接收。
下面是GSM03.40协议号码类型的解释:
 0 0 0   Unknown
 0 0 1   International number
 0 1 0   National number
 0 1 1   Network specific number
 1 0 0   Subscriber number
 1 0 1   Alphanumeric(coded according to TS03.38 7-bit default alphabet)
 1 1 0   Abbreviated number
 1 1 1   Reserved for extension
 ll not interpret reserved values but will store them as received.
       Bits 3,2,1,0:Numbering-plan-identification(号码鉴别),0000—未知,0001—ISDN/电话号码(E.164/E.163),1111—留作扩展;一般默认为0001,表示电话号码类型的。下面是GSM03.40号码鉴别的解释:
Bits3 2 1 0
0 0 0 0    Unknown
0 0 0 1    ISDN/telephone numbering plan (E.164/E.163)
0 0 1 1    Data numbering plan (X.121)
0 1 0 0    Telex numbering plan
1 0 0 0    National numbering plan
1 0 0 1    Private numbering plan
1 0 1 0    ERMES numbering plan (ETSI DE/PS 3 01-3)
1 1 1 1    Reserved for extension
All other values are reserved.
<2>短信中心号码:683108200805F0 
一个字节内反转,8613800280500,如果长度为奇数则需要加“F”补齐。比如号码为:+8613505165495,去掉"+"后在末尾添加F变为:8613505165495F,再将手机号码的奇数位和偶数位的相交换为683105155694F5
<3>FirstOctet字段:1119
     (1)11       包含TP-MTI(2bit),TP-RD(1bit),TP-VPF(2bit),TP-RP(1bit),TP-UDHI(1bit),TP-SRR(1bit)
二进制表示形式:0 0 0 10 0 01
TP-MTI:01 TP-Message-Type-Indicator(消息类型指示符)

     Bit1,0:00—读出(Deliver); 01—提交(Submit)
Bit1,0:01指示为SMS-SUBMIT类型 
下面是GSM03.40的解释:
 bit1 bit0  Message type
 0     0    SMS-DELIVER (in the direction SC to MS)
 0     0    SMS-DELIVER REPORT (in the direction MS to SC)
 1     0    SMS-STATUS-REPORT (in the direction SC to MS)
 1     0    SMS-COMMAND (in the direction MS to SC)
 0     1    SMS-SUBMIT (in the direction MS to SC)
 0     1    SMS-SUBMIT-REPORT (in the direction SC to MS)
 1    1      ReservedTP-RD:0  TP-Reject-Duplicates(是否拒绝相同重复消息)

   Bit2:0—接受复制; 1—拒绝复制
 
 Bit2:0   指示短消息中心接收未转发的具有相同TP-MR的消息。
 Bit 2:
 0    Instruct the SC to accept an SMS-SUBMIT for an SM still held in the  SC which has the same TP-MR and the same TP-DA as a previously submitted SM from the same OA.
 1    Instruct the SC to reject an SMS-SUBMIT for an SM still held in the   SC which has the same TP-MR and the same TP-DA as the  previously submitted SM from the same OA. In this case an  appropriate TP-FCS value will be returned in the SMS-SUBMIT-REPORT.
TP-VPF:10   TP-Validity-Period-Format(有效期格式)

Bit4,3::00—不提供(Not present);01—预留;  10—整型(标准),指使用相对格式;11—提供8位字节的一半(Semi-Octet Represented) 
下面是GSM03.40的解释:
bit4 bit3
0   0      TP-VP field not present
1   0      TP-VP field present and integer represented (relative)
0   1      Reserved
1   1      TP-VP field present and semi-octet represented (absolute)
TP-SRR:0    TP-Status-Report-Request
   Bit5:    1:需要报告,0:不需要报告。
Bit 5:
0       A status report is not requested
1       A status report is requested
TP-UDHI:0   TP-User-Data-Header-Indicator(用户数据头标示)   Bit6:   1:含头信息  0:不含头信息,指示这是一个SMS消息,没有用户数据头,EMS(增强消息业务)消息需要设置。图片铃声这些都是包含头部信息的.文本不包含头部信息
Bit  6
0     The TP-UD field contains only the short message
1     The beginning of the TP-UD field contains a Header in addition to the  short message
TP-RP:0     TP-Reply-Path(回复路径)   Bit7:    1:设置回复路径,0:没有设置回复路径。
下面是GSM03.40解释:
Bit 7:
0:  TP-Reply-Path parameter is not set in this SMS-SUBMIT/DELIVER
1:  TP-Reply-Path parameter is set in this SMS-SUBMIT/DELIVER
(2)消息参考值TP-MR (TP-Message-Reference):19如果使用"00" 值代表让电话自己设置消息参考值.
 
  <4> 对方号码字段:0D913105155694F5 
    0D:目标地址数字个数,共13个十进制数(不包括91和‘F’)
    91:地址类型,同短信中心号码设置.
   3105155694F5:目标手机号码。

<5>上层协议标识TP-PID(TP-Protocol-Identifier):00
     一般设置为00,表示普通GSM,点对点  <6> 数据编码设置TP-DCS(TP-Data-Coding-Scheme):08 
    指示TP-UD的编码方式。08代表Unicode方式。参照GSM03.38协议:
Bit 3,2
00    Default alphabet
01    8 bit
10    UCS2 (16bit) [10]
11    Reserved
  <7>有效期TP-VP(TP-Validity-Period):FF
    FF表示最大。
  <8> 用户数据长度TP-UDL(TP-User-Data-Length):4
      用户数据实际长度。注意不同编码下用户长度定义不同。
   <9>用户数据 :4F60597D     "你好"的Unicode编码
你:0x4F60;好:0x597D
  2:手机接收的PDU串
 0891683108200505F0040D91683105155694F5000850208151754500044F60597D
   <1>短信中心地址字段:0891683108200505F0,即是+8613800250500
 <2>FirstOctet :04        其二进制代码:00000100
    TP-MTI:00
    TP-MMS(TP-More-Message-to-Send):1 短信中心没有更多的消息发送
    TP-SRI: 0
    TP-UDHI:0
    TP-RP:  0
 <3>发送方号码 :0D91683105155694F5   即+8613505165495
 <4>协议标识: 00    TP-DCS 点对点
 <5>编码方式: 08    TP-DCS Unicode编码
   <6>短信中心时间    50208151754500  
     字节反转05/02/18 15:57:45 最后的00代表时区,这里为0
   <7>用户数据长度 :4 
 <8>用户数据:4F60597D      
   中文“你好”的Unicode编码

来源:http://www.cppblog.com/zhangyq/archive/2009/07/04/89245.html

2011-11-01 16:39:04 jhqin 阅读数 4357
  • 视频编解码之HEVC视频教程

    本课程主要介绍视频编解码的基础知识,并详细讲解新一代视频编解码标准HEVC。涉及到的课程内容有:数字视频格式、HEVC编码结构、帧间帧内预测、残差变换、残差变换系数量化、环路后处理、熵编码等。

    3636 人正在学习 去看看 梅奥
/* ----------------------------------------------------------
文件名称:Split.cs

作者:秦建辉

MSN:splashcn@msn.com
QQ:36748897

博客:http://blog.csdn.net/jhqin

开发环境:
    Visual Studio V2010
    .NET Framework 4 Client Profile

版本历史:    
    V1.0	2011年08月19日
			短信拆分部分
------------------------------------------------------------ */
using System;
using System.Collections.Generic;

namespace Splash.Phone
{
    /// <summary>
    /// 短信拆分部分
    /// </summary>
    public partial class SMS
    {
        /// <summary>
        /// 编码方案对应的最大用户数据长度
        /// </summary>
        private enum EnumUDL
        {
            BIT7UDL = 160,  // 7Bit编码允许的最大字符数
            BIT8UDL = 140,  // 8Bit编码允许的最大字节数
            UCS2UDL = 70    // UCS2编码允许的最大字符数
        }

        /// <summary>
        /// 用户数据内容拆分
        /// </summary>
        /// <param name="UDC">用户数据内容</param>
        /// <param name="UDH">用户数据头</param>
        /// <param name="DCS">编码方案</param>
        /// <returns>拆分内容列表</returns>
        private List<String> UDCSplit(String UDC, PDUUDH[] UDH = null, EnumDCS DCS = EnumDCS.UCS2)
        {   // 统计用户数据头长度
            Int32 UDHL = GetUDHL(UDH);

            if (DCS == EnumDCS.BIT7)
            {   // 7-Bit编码
                // 计算剩余房间数
                Int32 Room = (Int32)EnumUDL.BIT7UDL - (UDHL * 8 + 6) / 7;
                if (Room < 1)
                {
                    if (String.IsNullOrEmpty(UDC))
                        return new List<String>() { UDC };
                    else
                        return null;    // 超出范围
                }

                if (SeptetsLength(UDC) <= Room)
                {
                    return new List<String>() { UDC };
                }
                else
                {   // 需要拆分成多条短信
                    if (UDHL == 0) UDHL++;
                    if (mCSMIEI == EnumCSMIEI.BIT8)
                        UDHL += 5;  // 1字节消息参考号
                    else
                        UDHL += 6;  // 2字节消息参考号

                    // 更新剩余房间数
                    Room = (Int32)EnumUDL.BIT7UDL - (UDHL * 8 + 6) / 7;
                    if (Room < 1) return null;   // 超出范围

                    List<String> CSM = new List<String>();                    
                    Int32 i = 0;
                    while (i < UDC.Length)
                    {
                        Int32 Step = SeptetsToChars(UDC, i, Room);
                        if (i + Step < UDC.Length)
                            CSM.Add(UDC.Substring(i, Step));                        
                        else
                            CSM.Add(UDC.Substring(i));

                        i += Step;
                    }

                    return CSM;
                }
            }
            else
            {   // UCS2编码
                // 计算剩余房间数
                Int32 Room = ((Int32)EnumUDL.BIT8UDL - UDHL) >> 1;
                if(Room < 1)
                {
                    if (String.IsNullOrEmpty(UDC))
                        return new List<String>() { UDC };
                    else
                        return null;    // 超出范围
                }

                if (UDC == null || UDC.Length <= Room)
                {
                    return new List<String>() { UDC };
                }
                else
                {   // 需要拆分成多条短信
                    if (UDHL == 0) UDHL++;
                    if (mCSMIEI == EnumCSMIEI.BIT8)
                        UDHL += 5;  // 1字节消息参考号
                    else
                        UDHL += 6;  // 2字节消息参考号

                    // 更新剩余房间数
                    Room = ((Int32)EnumUDL.BIT8UDL - UDHL) >> 1;
                    if (Room < 1) return null;  // 超出范围

                    List<String> CSM = new List<String>();
                    for (Int32 i = 0; i < UDC.Length; i += Room)
                    {
                        if (i + Room < UDC.Length)
                            CSM.Add(UDC.Substring(i, Room));
                        else
                            CSM.Add(UDC.Substring(i));
                    }

                    return CSM;
                }
            }
        }

        /// <summary>
        /// 用户数据内容拆分
        /// </summary>
        /// <param name="UDC">用户数据内容</param>
        /// <param name="UDH">用户数据头</param>
        /// <returns>拆分内容列表</returns>
        private List<Byte[]> UDCSplit(Byte[] UDC, PDUUDH[] UDH = null)
        {   // 统计用户数据头长度
            Int32 UDHL = GetUDHL(UDH);
            
            // 8-Bit编码
            if (UDC == null || UDC.Length <= (Int32)EnumUDL.BIT8UDL - UDHL)
            {   // 不需要拆分
                return new List<Byte[]>() { UDC };
            }
            else
            {   // 需要拆分成多条短信
                if (UDHL == 0) UDHL++;
                if (mCSMIEI == EnumCSMIEI.BIT8)
                    UDHL += 5;  // 1字节消息参考号
                else
                    UDHL += 6;  // 2字节消息参考号

                // 短信内容拆分
                List<Byte[]> CSM = new List<Byte[]>();
                Int32 Step = (Int32)EnumUDL.BIT8UDL - UDHL;
                for (Int32 i = 0; i < UDC.Length; i += Step)
                {
                    CSM.Add((Byte[])UDC.SubArray(i, Step));
                }

                return CSM;
            }
        }

        /// <summary>
        /// 用户数据头长度
        /// </summary>
        /// <param name="UDH">用户数据头</param>
        /// <returns>用户数据头编码字节数</returns>
        private static Int32 GetUDHL(PDUUDH[] UDH)
        {
            if (UDH == null || UDH.Length == 0) return 0;

            Int32 UDHL = 1;     // 加上1字节的用户数据头长度
            foreach (PDUUDH IE in UDH)
            {
                UDHL += IE.IED.Length + 2;  // 信息元素标识+信息元素长度+信息元素数据
            }

            return UDHL;
        }

        /// <summary>
        /// 计算字符串需要的7-Bit编码字节数
        /// </summary>
        /// <param name="source">字符串</param>
        /// <returns>7-Bit编码字节数</returns>
        private static Int32 SeptetsLength(String source)
        {
            if (String.IsNullOrEmpty(source)) return 0;
            
            Int32 Length = source.Length;
            foreach (Char Letter in source)
            {
                UInt16 Code = Convert.ToUInt16(Letter);
                if (UCS2ToBIT7.ContainsKey(Code))
                {
                    if (UCS2ToBIT7[Code] > 0xFF) Length++;
                }
            }

            return Length;
        }

        /// <summary>
        /// 判断字符串是否在GSM缺省字符集内
        /// </summary>
        /// <param name="source">要评估的字符串</param>
        /// <returns>
        ///     true:在GSM缺省字符集内,可以使用7-Bit编码
        ///     false:不在GSM缺省字符集内,只能使用UCS2编码
        /// </returns>
        private static Boolean isGSMString(String source)
        {
            if (String.IsNullOrEmpty(source)) return true;

            foreach (Char Letter in source)
            {
                UInt16 Code = Convert.ToUInt16(Letter);
                if (!(isBIT7Same(Code) || UCS2ToBIT7.ContainsKey(Code)))
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// 将7-Bit编码字节数换算成UCS2编码字符数
        /// </summary>
        /// <param name="source">字符串</param>
        /// <param name="index">起始索引号</param>
        /// <param name="septets">要换算的7-Bit编码字节数</param>
        /// <returns>UCS2编码字符数</returns>
        private static Int32 SeptetsToChars(String source, Int32 index, Int32 septets)
        {
            if (String.IsNullOrEmpty(source)) return 0;

            Int32 Count = 0;
            Int32 i = index;
            for (; i < source.Length; i++)
            {
                UInt16 Code = Convert.ToUInt16(source[i]);
                if (UCS2ToBIT7.ContainsKey(Code) && UCS2ToBIT7[Code] > 0xFF)
                {
                    Count++;
                }
                
                if (++Count >= septets)
                {
                    if (Count == septets) i++;
                    break;
                }
            }

            return i - index;
        }

        /// <summary>
        /// 在用户数据头中增加长短信信息元素
        /// </summary>
        /// <param name="UDH">原始用户数据头</param>
        /// <param name="CSMMR">消息参考号</param>
        /// <param name="Total">短消息总数</param>
        /// <param name="Index">短消息序号</param>
        /// <returns>更新后的用户数据头</returns>
        private PDUUDH[] UpdateUDH(PDUUDH[] UDH, Int32 CSMMR, Int32 Total, Int32 Index)
        {
            List<PDUUDH> CSMUDH;
            if (UDH == null || UDH.Length == 0)
                CSMUDH = new List<PDUUDH>(1);
            else
                CSMUDH = new List<PDUUDH>(UDH);
            
            if (mCSMIEI == EnumCSMIEI.BIT8)
            {
                Byte[] IED = new Byte[3]{(Byte)(CSMMR & 0xFF), (Byte)Total, (Byte)(Index + 1)};
                CSMUDH.Insert(0, new PDUUDH { IEI = 0, IED = IED });
            }
            else
            {
                Byte[] IED = new Byte[4] { (Byte)((CSMMR >> 8) & 0xFF), (Byte)(CSMMR & 0xFF), (Byte)Total, (Byte)(Index + 1) };
                CSMUDH.Insert(0, new PDUUDH { IEI = 8, IED = IED });
            }

            return CSMUDH.ToArray();
        }
    }
}

2017-03-17 17:10:45 chenzhentao 阅读数 1201
  • 视频编解码之HEVC视频教程

    本课程主要介绍视频编解码的基础知识,并详细讲解新一代视频编解码标准HEVC。涉及到的课程内容有:数字视频格式、HEVC编码结构、帧间帧内预测、残差变换、残差变换系数量化、环路后处理、熵编码等。

    3636 人正在学习 去看看 梅奥

写在开始,这是一篇非常非常不完善的笔记类的文章,只是我初步的认识,可能会有错误,仅供参考!

最近在做Android CDMA 短信编解码相关的工作,记录一下Android对CDMA Sms的编解码操作。包括Android CDMA SMS相关类结构,数据结构,数据处理流程等内容,持续更新。

类结构图

Android Cdma Sms编解码相关类

以下是短信地址相关的数据结构

  • SmsAddress:存储短信电话号码的数据结构,主要数据单元:
    • address:String,address用于存储解码好的电话号码用于终端显示。
    • origBytes:byte[].其中origByets用于存放编码好的电话号码,用于网络传输。
    • ton,TON_INTERNATIONAL / TON_NATIONAL等标识地址类型
    • toa,自定义成员,非3GPP2规范定义
  • CdmaSmsAddress:作为SmsAddress的子类,用于存放CDMA短信电话号码的数据结构。因为其父类已经包含电话号码所需的数据单元,因此该类只为符合CDMA编码规范存储控制单元。
    • digitMode,用于存储电话号码编码格式,有4bit和8bit编码。例如135,使用4bit编码可以表示0x13,0x50两个byte就可以表示。但是如果8bit编码就是0x01,0x03,0x05需要三个bit才可以编码。0代表4bit,1代表8bit
    • numberMode,numberMode用于标识当前地址是否是一个data network address(0,不是。1,是)
    • numberOfDigits,标识当前地址长度。
    • numberPlan, 如果numberMode是0,digitMode是1则numberPlan应该被定义(4bit)。可选值NUMBERING_PLAN_UNKNOWN , NUMBERING_PLAN_TELEPHONY
  • CdmaSmsSubAddress ,CdmaSms的子地址
    • origBytes包含子地址的真实地址数据

以下是短信头相关的类

短信头的作用,举个例子就是对于长短信,(英文大于160字符,Unicode字符大于70)需要分成多条发送,此时就需要在每条短信前面加上短信头,短信头的长度不固定,并且需要占用短信内容长度。例如短信头占用5byte,Unicode字符就只能存放(140-5)/2 = 67个了。

  • SmsHeader::ConcatRef做长短信连接的短信头数据结构。负责标识当前短信是长短信的第几条,隶属于哪一条长短信。
    • refNumber 当前短信的序列号,类似ID
    • seqNumber 当前短信的序号,类似3/5中的3,意思是五条短信中的第三条
    • msgCount 当前长短信的总条数,类似3/5中的5.
    • isEightBits 标识当前refNumber是8bit还是16bit,在编解码的时候都会根据这个变量确定refNumber的真实值

其他几个短信头类还没遇到过,作用不了解,遇到之后补上

  • SmsHeader 包含短信头各个子数据和一些附属属性的短信头总括
    • mPortAddrs 端口地址
    • mConcatRef 长短新拼接需要的数据结构
    • languageTable GSM定义的字符表,编码和解码都通过查表解决.字符表定义可以参考GSMAplhaBet.java
    • languageShiftTable 扩展字符表,用于基础字符表的补充

至此短信地址和短信头的数据结构就简单罗列完毕,下面就说短信内容相关的类

  • UserData 包含短信头,短信内容,编码方式,消息类型等数据,可以看到数据越来越丰富了
    • userDataHeader 短信头,具体作用见SmsHeader的介绍
    • msgEncoding 短信编码方式,常见编码方式7bit_ascii,UNICODE_16等等.这里说道的编码方式就会影响到一条短信最终可以成在内容的数量了.例如对于ascii码的内容,范围在0x00~0x7F.最高位为0,所以需要7bit就可以编码一个字符.最终140byte里面就可以保存160个ascii字符.
    • msgType 并不知道这个是干啥用的
    • paddingBits 对于不满8bit的数据占用8bit后剩余的部分.
    • numFields 短信长度(包括短信头的部分和短信内容的长度)
    • payloadStr 字符串类型的短信内容
  • BearerData 包含UserData(短信内容+短信头),时间戳,优先级,ID,短信类型,发送报告,已读报告,电话号码等字段的数据结构.BearerData负责这些数据单元的编码和解码工作.既可以通过encode将数据转换为pdu也可以通过decode将pdu转换成数据字段.
    • messageType DELIVERY,SUBMIT, DELIVERY_REPORT,SUBMIT_REPORT, USER_ACK,READ_ACK以上可能的几个取值,发送报告,阅读报告,发送等类型
    • messageId 信息ID,目前没有发现Android哪里在用.
    • priority 信息优先级
    • privacy 私密等级,无,有,机密,绝密
    • displayMode 定义显示短信的时间,立刻现实/默认设置/用户自定义
    • language 语种
    • errorCalss/messageStatus 消息状态,错误状态封装状态码
    • userData 封装了短信内容和短信头的数据
    • userResponseCode 用户在收到短信之后回复给服务器的响应码
    • msgCenterTimeStamp 短信中心时间戳
    • userAckReq/deliveryAckReq/readAckReq/reportReq 各种响应码的标志
    • depositIndex 看不懂描述系列~,有兴趣的可以去看BearerData.java注释内容有写
    • callbackNumber 可以回拨电话的地址

简单介绍BearerData.java里面包含的几个成员.可以看到BearerData已经包含了电话号码,短信内容,编码方式,时间戳等基本信息,也包含了像是优先级,是否需要发送报告等控制信息,可以说已经包含了一条短信的基本要素.BearerData的作用就是将这些基本要素编码成pdu发送,或者从pdu中解码出这些基本信息.

  • SmsEnvelope 这个是信封?丰富了消息类型,收件人,发件人,消息内容(bearerData),状态码
    • messageType 这里的信息类型就是具体短信类型了.Point_To_Point(点对点信息),Broadcast(广播),Acknowledge(通知)
    • teleService 这个..teleService,不知道干啥用
    • origAddress 发送端地址
    • destAddress 收件人地址
    • bearerData bearerData的pdu数据,byte[]

到这里CDMASms编解码相关的类就介绍完了,包含了CDMA短信所需要的数据块.后面我会再尝试更新CDMA短信的编码方式和具体的代码流程.

    -
没有更多推荐了,返回首页