/* ------------------------------------------------------------------ * Copyright (C) 1998-2009 PacketVideo * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. * See the License for the specific language governing permissions * and limitations under the License. * ------------------------------------------------------------------- */ #include "aac_media_info_parser.h" #include "oscl_string_utils.h" #include "oscl_string_containers.h" SDP_ERROR_CODE SDPAACMediaInfoParser::parseMediaInfo(const char *buff, const int index, SDPInfo *sdp, payloadVector payload_vec, bool isSipSdp, int alt_id, bool alt_def_id) { const char *current_start = buff; //Pointer to the beginning of the media text const char *end = buff + index; //Pointer to the end of the media text const char *line_start_ptr, *line_end_ptr; int decLength = 0; int fmtp_cnt = 0; SDPAllocDestructDealloc<uint8> SDP_alloc; while (get_next_line(current_start, end, line_start_ptr, line_end_ptr)) { if ((!oscl_strncmp(line_start_ptr, "a=alt:", oscl_strlen("a=alt:"))) && (alt_def_id == false)) { line_start_ptr += oscl_strlen("a=alt:"); for (; *line_start_ptr != ':'; line_start_ptr++); line_start_ptr = line_start_ptr + 1; } if (!oscl_strncmp(line_start_ptr, "a=fmtp:", oscl_strlen("a=fmtp:"))) { const char *tmp_start_line, *tmp_end_line; fmtp_cnt++; tmp_start_line = line_start_ptr + oscl_strlen("a=fmtp:"); tmp_start_line = skip_whitespace(tmp_start_line, line_end_ptr); if (tmp_start_line >= line_end_ptr) { break; } tmp_end_line = skip_to_whitespace(tmp_start_line, line_end_ptr); if (tmp_end_line < tmp_start_line) { break; } tmp_start_line = tmp_end_line + 1; tmp_start_line = skip_whitespace(tmp_start_line, line_end_ptr); if (tmp_start_line >= line_end_ptr) { break; } int ii = 0; const char *temp = tmp_start_line; for (ii = 0; ii < (line_end_ptr - tmp_start_line) ; ii++) { if ((tmp_start_line[ii] == ';') || (ii == (line_end_ptr - tmp_start_line - 1))) { tmp_end_line = tmp_start_line + ii; if ((line_end_ptr - tmp_start_line - 1) == ii) { tmp_end_line++; } if (!oscl_strncmp(temp, "config=", oscl_strlen("config="))) { uint32 currentLength; temp += oscl_strlen("config="); temp = skip_whitespace(temp, line_end_ptr); if (temp >= line_end_ptr) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAACMediaInfoParser::parseMediaInfo - no data in config= field")); return SDP_BAD_MEDIA_FMTP; } currentLength = (int)(tmp_end_line - temp) / 2; if (decLength < (int) currentLength) decLength = currentLength; } if (tmp_end_line != line_end_ptr) temp = tmp_end_line + 1; temp = skip_whitespace(temp, line_end_ptr); if (temp >= line_end_ptr) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAACMediaInfoParser::parseMediaInfo - Format in a=fmtp line is incorrect")); return SDP_BAD_MEDIA_FMTP; } } } } current_start = line_end_ptr + 1; } if (fmtp_cnt == 0) // a=fmtp field not found { PVMF_SDP_PARSER_LOGERROR((0, "SDPAACMediaInfoParser::parseMediaInfo - a=fmtp field not found")); return SDP_FAILURE_NO_FMTP_FIELD; } bool altMedia = false; if (!alt_id || (alt_def_id == true)) altMedia = false; else altMedia = true; //Allocate media info class here void *memory = sdp->alloc(sizeof(aac_mediaInfo), altMedia); if (NULL == memory) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAACMediaInfoParser::parseMediaInfo - unable to allocate memory to media parser")); return SDP_NO_MEMORY; } else { aac_mediaInfo *aacA = OSCL_PLACEMENT_NEW(memory, aac_mediaInfo()); aacA->setMediaInfoID(sdp->getMediaObjectIndex()); // Allocate memory to the payload specific objects for (uint32 ii = 0; ii < payload_vec.size(); ii++) { void* mem = aacA->alloc(sizeof(AacPayloadSpecificInfoType)); if (mem == NULL) { return SDP_NO_MEMORY; } else { OSCL_PLACEMENT_NEW(mem, AacPayloadSpecificInfoType(payload_vec[ii])); } } if (alt_id && !alt_def_id) { sdp->copyFmDefMedia(aacA); aacA->resetAlternateTrackId(); aacA->resetDependentTrackId(); } SDP_ERROR_CODE status = baseMediaInfoParser(buff, aacA, index, alt_id, alt_def_id, isSipSdp); if (status != SDP_SUCCESS) { return status; } current_start = buff; while (get_next_line(current_start, end, line_start_ptr, line_end_ptr)) { switch (*line_start_ptr) { case 'a': { const char *sptr; if ((!oscl_strncmp(line_start_ptr, "a=alt:", oscl_strlen("a=alt:"))) && (alt_def_id == false)) { line_start_ptr += oscl_strlen("a=alt:"); for (; *line_start_ptr != ':'; line_start_ptr++); line_start_ptr = line_start_ptr + 1; } if (!oscl_strncmp(line_start_ptr, "a=lang:", oscl_strlen("a=lang:"))) { sptr = line_start_ptr + oscl_strlen("a=lang:"); sptr = skip_whitespace(sptr, line_end_ptr); if (sptr >= line_end_ptr) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAACMediaInfoParser::parseMediaInfo - a=lang field incorrect")); return SDP_BAD_MEDIA_LANG_FIELD; } OsclMemoryFragment memFrag; memFrag.ptr = (void*)sptr; memFrag.len = (line_end_ptr - sptr); ((aac_mediaInfo*)aacA)->setLang(memFrag); } if (!oscl_strncmp(line_start_ptr, "a=fmtp:", oscl_strlen("a=fmtp:"))) { const char *tmp_start_line, *tmp_end_line; tmp_start_line = line_start_ptr + oscl_strlen("a=fmtp:"); tmp_start_line = skip_whitespace(tmp_start_line, line_end_ptr); if (tmp_start_line >= line_end_ptr) { break; } tmp_end_line = skip_to_whitespace(tmp_start_line, line_end_ptr); if (tmp_end_line < tmp_start_line) { break; } uint32 payloadNumber; if (PV_atoi(tmp_start_line, 'd', (tmp_end_line - tmp_start_line), payloadNumber) == false) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAACMediaInfoParser::parseMediaInfo - a=fmtp field format is incorrect")); return SDP_BAD_MEDIA_FMTP; } else { int p; if (!aacA->lookupPayloadNumber(payloadNumber, p)) { fmtp_cnt--; break; } } // payloadNumber is present in the mediaInfo. get the payload // Specific pointer corresponding to this payload AacPayloadSpecificInfoType* payloadPtr = (AacPayloadSpecificInfoType*)aacA->getPayloadSpecificInfoTypePtr(payloadNumber); PVMF_SDP_PARSER_LOGINFO((0, "SDPAacMediaInfoParser::parseMediaInfo - processing payload number : %d", payloadNumber)); tmp_start_line = tmp_end_line + 1; tmp_start_line = skip_whitespace(tmp_start_line, line_end_ptr); if (tmp_start_line >= line_end_ptr) { break; } int ii = 0; const char *temp = tmp_start_line; for (ii = 0; ii < (line_end_ptr - tmp_start_line) ; ii++) { if ((tmp_start_line[ii] == ';') || (ii == (line_end_ptr - tmp_start_line - 1))) { tmp_end_line = tmp_start_line + ii; if (ii == (line_end_ptr - tmp_start_line - 1)) { tmp_end_line += 1; } if (!oscl_strncmp(temp, "config=", oscl_strlen("config="))) { uint8 *mptr = SDP_alloc.allocate(decLength); OsclRefCounterSA< SDPAllocDestructDealloc<uint8> > *refcnt = new OsclRefCounterSA< SDPAllocDestructDealloc<uint8> >(mptr); OsclSharedPtr<uint8> decInfo(mptr, refcnt); temp += oscl_strlen("config="); temp = skip_whitespace(temp, line_end_ptr); if (temp >= line_end_ptr) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAACMediaInfoParser::parseMediaInfo - a=fmtp field format is incorrect for config= field")); return SDP_BAD_MEDIA_FMTP; } decLength = (int)(tmp_end_line - temp) / 2; int idx = 0; for (idx = 0; idx < decLength; idx++) { uint32 val; if (PV_atoi((temp + 2*idx), 'x', 2, val) == false) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAACMediaInfoParser::parseMediaInfo - a=fmtp field format is incorrect for config= field")); return SDP_BAD_MEDIA_FMTP; } *(decInfo + idx) = (uint8) val; } if (payloadPtr) { payloadPtr->setDecoderSpecificInfo(decInfo); payloadPtr->setDecoderSpecificInfoSize(decLength); } else { PVMF_SDP_PARSER_LOGERROR((0, "SDPAACMediaInfoParser::parseMediaInfo - a=fmtp field format is incorrect for payload")); return SDP_PAYLOAD_MISMATCH; } } // add code for cpresent flag if (!oscl_strncmp(temp, "cpresent=", oscl_strlen("cpresent="))) { temp += oscl_strlen("cpresent="); temp = skip_whitespace(temp, line_end_ptr); if (temp > line_end_ptr) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAACMediaInfoParser::parseMediaInfo - a=fmtp format is incorrect for cpresent= field")); return SDP_BAD_MEDIA_FMTP; } uint32 cpresent; //Assuming that the possible values are either 0 or 1 if (PV_atoi(temp, 'd', tmp_end_line - temp, cpresent) == true) { if (payloadPtr) payloadPtr->setcpresent(cpresent ? true : false); else return SDP_PAYLOAD_MISMATCH; } } if (!oscl_strncmp(temp, "SBR-enabled=", oscl_strlen("SBR-enabled="))) { temp += oscl_strlen("SBR-enabled="); temp = skip_whitespace(temp, line_end_ptr); if (temp > line_end_ptr) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAACMediaInfoParser::parseMediaInfo - a=fmtp format is incorrect for SBR-enabled= field")); return SDP_BAD_MEDIA_FORMAT; } uint32 sbrEn; //Assuming that the possible values are either 0 or 1 if (PV_atoi(temp, 'd', tmp_end_line - temp, sbrEn) == true) { if (payloadPtr) payloadPtr->setAACplusSBRenabled(sbrEn ? true : false); else return SDP_PAYLOAD_MISMATCH; } } if (!oscl_strncmp(temp, "decode_buf=", oscl_strlen("decode_buf="))) { temp += oscl_strlen("decode_buf="); temp = skip_whitespace(temp, tmp_end_line); if (temp > tmp_end_line) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAACMediaInfoParser::parseMediaInfo - a=fmtp format is incorrect for decode_buf= field")); return SDP_BAD_MEDIA_FORMAT; } uint32 dec; if (PV_atoi(temp, 'd', tmp_end_line - temp, dec) == true) { if (payloadPtr) payloadPtr->setMaxBufferSize(dec); else return SDP_PAYLOAD_MISMATCH; } } if (tmp_end_line != line_end_ptr) temp = tmp_end_line + 1; temp = skip_whitespace(temp, line_end_ptr); if (temp >= line_end_ptr) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAACMediaInfoParser::parseMediaInfo - a=fmtp format is bad")); return SDP_BAD_MEDIA_FORMAT; } } } } } break; default: break; } current_start = line_end_ptr; } sessionDescription *session = sdp->getSessionInfo(); const char *altGroupBW = session->getAltGroupBW(); int length = session->getAltGroupBWLength(); if (length > 0) { status = setDependentMediaId(altGroupBW, length, aacA, alt_id); if (status != SDP_SUCCESS) return SDP_BAD_MEDIA_ALT_ID; } const char *altGroupLANG = session->getAltGroupLANG(); length = session->getAltGroupLANGLength(); if (length > 0) { status = setDependentMediaId(altGroupLANG, length, aacA, alt_id); if (status != SDP_SUCCESS) return SDP_BAD_MEDIA_ALT_ID; } if (aacA->getCFieldStatus() || session->getCFieldStatus()) { //if sample rate is zero override with defaults Oscl_Vector<PayloadSpecificInfoTypeBase*, SDPParserAlloc> payloadSpecificInfoVector = aacA->getPayloadSpecificInfoVector(); for (int ii = 0; ii < (int)payloadSpecificInfoVector.size(); ii++) { if (payloadSpecificInfoVector[ii]->getSampleRate() == 0) { payloadSpecificInfoVector[ii]->sampleRate = PVMF_SDP_DEFAULT_LATM_SAMPLE_RATE; } } return SDP_SUCCESS; } else { return SDP_FAILURE_NO_C_FIELD; } } }