📄 sdpmdparse.cpp
字号:
char* pCur = pLine;
if (ScanForDelim(pCur, ':'))
{
char* pColon = pCur;
*pCur++ = '\0';
char* pEnd = 0;
ULONG32 ulBwValue = strtoul(pCur, &pEnd, 10);
if (*pCur && !*pEnd)
{
const char* pBwKey = 0;
res = HXR_OK;
if (!strcasecmp(pLine, "AS"))
{
// a=AvgBitRate has the higher precedence...
ULONG32 ulTmp;
if (!SUCCEEDED(pHdr->GetPropertyULONG32("AvgBitRate",
ulTmp)))
{
// use this as a default.
// it's kilobits per sec....
pBwKey = "AvgBitRate";
ulBwValue *= 1000;
}
}
else if (!strcasecmp(pLine, "RR"))
{
pBwKey = "RtcpRRRate";
}
else if (!strcasecmp(pLine, "RS"))
{
pBwKey = "RtcpRSRate";
}
else
{
res = HXR_NOT_SUPPORTED;
}
if (pBwKey)
{
AddULONG32(pHdr, pBwKey, ulBwValue);
}
}
*pColon = ':';
}
return res;
}
HX_RESULT SDPMediaDescParser::ParseFieldValue(char*& pValue,
FieldType& fieldType) const
{
HX_RESULT res = HXR_OK;
char* pCur = pValue;
// Look for the following forms
// a=anInt:integer;43
// a=aString:string;"this is a string"
// a=aBuffer:buffer;"TWFjIFRWAA=="
// Assume we don't know the type.
fieldType = ftUnknown;
if (ScanForDelim(pCur, ';'))
{
// Replace the ';' with a '\0' so we
// can check to see if it matches the known
// types
char* pSemiColon = pCur;
*pCur++ = '\0';
if (!strcmp(pValue, "integer"))
{
// Update the value pointer to the
// start of the integer value
pValue = pCur;
fieldType = ftULONG32;
}
else if (!strcmp(pValue, "string"))
{
fieldType = ftString;
}
else if (!strcmp(pValue, "buffer"))
{
fieldType = ftBuffer;
}
if ((fieldType == ftString) || (fieldType == ftBuffer))
{
BOOL bFailed = TRUE;
// Look for starting '"'
if (*pCur == '"')
{
pCur++; // skip '"'
if (*pCur)
{
// Store start of the string
char* pStrStart = pCur;
// Create temporary buffer for unescaping
char* pTmpBuf = new char[strlen(pStrStart) + 1];
if (pTmpBuf)
{
char* pDest = pTmpBuf;
// Copy string into pTmpBuf and
// unescape any escape sequences
while (*pCur && *pCur != '"')
{
if (*pCur == '\\')
{
*pCur++; // skip '\\'
}
*pDest++ = *pCur++;
}
// Make sure the last character is a '"'
if (*pCur == '"')
{
// Replace ending '"' with '\0'
*pDest = '\0';
// Replace escaped string with
// unescaped string.
strcpy(pStrStart, pTmpBuf);
// Update the value pointer to the
// start of the string value
pValue = pStrStart;
bFailed = FALSE;
}
delete [] pTmpBuf;
}
}
}
if (bFailed)
{
fieldType = ftUnknown;
}
}
if (fieldType == ftUnknown)
{
// This is not a type we recognize.
// Replace the '\0' with a ';' so the
// value is the way it was before.
*pSemiColon = ';';
}
}
return res;
}
HX_RESULT SDPMediaDescParser::HandleSpecialFields(const char* pFieldName,
char* pFieldValue,
IHXValues* pHdr)
{
HX_RESULT res = HXR_FAILED;
if (!strcasecmp("Range", pFieldName))
{
res = HandleRangeField(pFieldValue, pHdr);
}
else if (!strcasecmp("length", pFieldName))
{
res = HandleLengthField(pFieldValue, pHdr);
}
else if (!strcasecmp("rtpmap", pFieldName))
{
res = HandleRTPMapField(pFieldValue, pHdr);
}
else if (!strcasecmp("fmtp", pFieldName))
{
res = HandleFMTPField(pFieldValue, pHdr);
}
else if (!strcasecmp("ptime", pFieldName))
{
// a=ptime:43
AddULONG32(pHdr, "Ptime", strtol(pFieldValue, 0, 10));
res = HXR_OK;
}
else if (!strcasecmp("x-bufferdelay", pFieldName))
{
// a=x-bufferdelay:234
// x-bufferdelay units are 1/1000 of a sec
res = HandlePrerollField(pFieldValue, 1000, pHdr);
}
else if (!strcasecmp("x-initpredecbufperiod", pFieldName))
{
// 3GPP 26.234 Annex G field
// a=x-initpredecbufperiod:45000
// x-initpredecbufperiod units are 1/90000 of a sec
res = HandlePrerollField(pFieldValue, 90000, pHdr);
}
else if (!strcasecmp("x-predecbufsize", pFieldName))
{
// 3GPP 26.234 Annex G field
// a=x-predecbufsize:45000
// x-predecbufsize units are bytes
AddULONG32(pHdr, "x-predecbufsize", strtoul(pFieldValue, 0, 10));
res = HXR_OK;
}
else if (!strcasecmp("SdpplinVersion", pFieldName))
{
res = checkVersion(strtol(pFieldValue, 0, 10));
if (HXR_FAIL == res)
{
// need to update...
// this flag causes to exit in "m=" case
res = HXR_REQUEST_UPGRADE;
}
}
else if (!strcasecmp("control", pFieldName))
{
AddString(pHdr, "Control", pFieldValue);
res = HXR_OK;
}
else
{
res = HXR_NOT_SUPPORTED;
}
return res;
}
HX_RESULT SDPMediaDescParser::HandleRangeField(char* pFieldValue,
IHXValues* pHdr)
{
char* pCur = pFieldValue;
ULONG32 duration = 0;
BOOL bIsLegal = TRUE;
if (ScanForDelim(pCur, '='))
{
// replace '=' with '\0'
*pCur++ = '\0';
if (!strcasecmp(pFieldValue, "npt"))
{
// Look for the following npt forms
// a=range:npt=-xxx
// a=range:npt=xxx-
// a=range:npt=xxx-xxx
char* pLeftVal = pCur;
if (ScanForDelim(pCur, '-'))
{
// replace '-' with '\0'
*pCur++ = '\0';
NPTime left(pLeftVal);
NPTime right(pCur);
if (*pCur)
{
// a=range:npt=xxx-xxx
duration = (UINT32)(right - left);
m_bDefiniteDuration = TRUE;
}
else
{
// a=range:npt=xxx-
// Treat open-ended play ranges as live streams
// unless it is overridden by a media range.
}
}
else
{
// This must be the following illegal form
// a=range:npt=xxx
bIsLegal = FALSE;
}
}
}
else
{
duration = strtol(pFieldValue, 0, 10);
}
if (bIsLegal)
{
if (0 == m_ulDefaultDuration)
{
m_ulDefaultDuration = duration;
}
AddULONG32(pHdr, "Duration", duration);
}
return HXR_OK;
}
HX_RESULT SDPMediaDescParser::HandleLengthField(char* pFieldValue,
IHXValues* pHdr)
{
HX_RESULT res = HXR_FAILED;
char* pCur = pFieldValue;
ULONG32 duration = 0;
BOOL bIsLegal = TRUE;
// Look for the following npt form
// a=length:npt=xxx
if (ScanForDelim(pCur, '='))
{
char* pEqual = pCur;
// replace '=' with '\0'
*pCur++ = '\0';
if (!strcasecmp(pFieldValue, "npt") && *pCur)
{
NPTime dTime(pCur);
duration = (UINT32)dTime;
res = HXR_OK;
}
else
{
// Put back '=' character
*pEqual = '=';
}
}
else
{
duration = strtol(pFieldValue, 0, 10);
res = HXR_OK;
}
if (duration)
{
m_bDefiniteDuration = TRUE;
}
if (0 == m_ulDefaultDuration)
{
m_ulDefaultDuration = duration;
}
AddULONG32(pHdr, "Duration", duration);
return res;
}
HX_RESULT SDPMediaDescParser::HandleRTPMapField(char* pFieldValue,
IHXValues* pHdr)
{
HX_RESULT res = HXR_FAILED;
// e.g. a=rtpmap:101 xxx/90000/2
char* pCur = 0;
UINT32 payload = strtol(pFieldValue, &pCur, 10);
ULONG32 rtpPayloadType = 0;
res = pHdr->GetPropertyULONG32("RTPPayloadType", rtpPayloadType);
if (*pFieldValue && (*pCur == ' '))
{
SkipSpaces(pCur);
// there could be multiple of these...
if (payload == rtpPayloadType)
{
CHXString mimeType(m_mediaType);
res = getRTPMapInfo(pCur, mimeType, pHdr);
/* make sure there is no mime type set!
* MimeType from m= && a=rtpmap has the lowest precedence.
* a=mimetype -> mimetype table -> this mimetype
*/
IHXBuffer* pMimeType = 0;
if (!SUCCEEDED(pHdr->GetPropertyCString(
"MimeType", pMimeType)))
{
AddString(pHdr, "MimeType", mimeType);
}
HX_RELEASE(pMimeType);
}
}
return res;
}
HX_RESULT SDPMediaDescParser::HandleFMTPField(char* pFieldValue,
IHXValues* pHdr)
{
// e.g. a=fmtp:101 emphasis=50/15;foo=bar
char* pCur = 0;
UINT32 payload = strtol(pFieldValue, &pCur, 10);
ULONG32 rtpPayloadType = 0;
HX_RESULT res = pHdr->GetPropertyULONG32("RTPPayloadType", rtpPayloadType);
if (*pFieldValue && *pCur == ' ')
{
SkipSpaces(pCur);
// If the RTPPayloadType field is present, compare it
// to the value in the fmtp field.
// There could be multiple of these...
if ((HXR_OK != res) || (payload == rtpPayloadType))
{
AddString(pHdr, "PayloadParameters", pCur);
CHXFMTPParser fmtp(m_pCCF);
res = fmtp.Parse(pCur, pHdr);
}
}
return res;
}
HX_RESULT SDPMediaDescParser::HandlePrerollField(char* pFieldValue,
ULONG32 ulPrerollUnits,
IHXValues* pHdr)
{
ULONG32 ulPreroll = 0;
if (HXR_OK != pHdr->GetPropertyULONG32("Preroll", ulPreroll))
{
ULONG32 ulValue = strtoul(pFieldValue, 0, 10);
// Convert Preroll value to milliseconds
ulPreroll = (ulValue / ulPrerollUnits) * 1000;
ulPreroll += ((ulValue % ulPrerollUnits) * 1000) / ulPrerollUnits;
AddULONG32(pHdr, "Preroll", ulPreroll);
}
return HXR_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -