/* ------------------------------------------------------------------ * 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 "m4v_media_info_parser.h" #include "oscl_string_utils.h" #include "oscl_string_containers.h" SDP_ERROR_CODE SDPMPEG4MediaInfoParser::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 VOLLength = 0; int fmtp_cnt = 0 ; bool framesize_found_in_fmtp = false; 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:"))) { char *tmp_start_line, *tmp_end_line; fmtp_cnt++ ; tmp_start_line = (char *)line_start_ptr + oscl_strlen("a=fmtp:"); tmp_start_line = (char *)skip_whitespace(tmp_start_line, line_end_ptr); if (tmp_start_line >= line_end_ptr) { break; } tmp_end_line = (char *)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 = (char *)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="))) { int currentVOLLength; temp += oscl_strlen("config="); temp = skip_whitespace(temp, line_end_ptr); if (temp >= line_end_ptr) { PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - Bad config field")); return SDP_BAD_MEDIA_FMTP; } currentVOLLength = (int)(tmp_end_line - temp) / 2; if (VOLLength < currentVOLLength) VOLLength = currentVOLLength; } 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, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format")); return SDP_BAD_MEDIA_FMTP; } } } } current_start = line_end_ptr + 1; } if (fmtp_cnt == 0 && isSipSdp == false) { PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - No fmtp line found")); return SDP_BAD_MEDIA_FORMAT; } if (VOLLength < 0) { VOLLength = 0; } bool altMedia = false; if (!alt_id || (alt_def_id == true)) altMedia = false; else altMedia = true; void *memory = sdp->alloc(sizeof(m4v_mediaInfo), altMedia); if (NULL == memory) { PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - memory allocation failure")); return SDP_NO_MEMORY; } else { m4v_mediaInfo *m4Video = OSCL_PLACEMENT_NEW(memory, m4v_mediaInfo()); m4Video->setMediaInfoID(sdp->getMediaObjectIndex()); // Allocate memory to the payload specific objects for (uint32 ii = 0; ii < payload_vec.size(); ii++) { void* mem = m4Video->alloc(sizeof(M4vPayloadSpecificInfoType)); if (mem == NULL) { PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Memory allocation failure")); return SDP_NO_MEMORY; } else { M4vPayloadSpecificInfoType* payload = OSCL_PLACEMENT_NEW(mem, M4vPayloadSpecificInfoType(payload_vec[ii])); (void) payload; } } if (alt_id && !alt_def_id) { sdp->copyFmDefMedia(m4Video); //empty alternate & default track ID vectors. m4Video->resetAlternateTrackId(); m4Video->resetDependentTrackId(); } SDP_ERROR_CODE status = baseMediaInfoParser(buff, m4Video, 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=framerate:", oscl_strlen("a=framerate:"))) { sptr = line_start_ptr + oscl_strlen("a=framerate:"); sptr = skip_whitespace(sptr, line_end_ptr); if (sptr >= line_end_ptr) { PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=framerate line format")); return SDP_BAD_MEDIA_FRAME_RATE; } OsclFloat rate; if (!PV_atof(sptr, line_end_ptr - sptr, rate)) return SDP_BAD_MEDIA_FORMAT; ((m4v_mediaInfo *)m4Video)->setFrameRate(rate); } if (!oscl_strncmp(line_start_ptr, "a=I_frame_interval:", oscl_strlen("a=I_frame_interval:"))) { sptr = line_start_ptr + oscl_strlen("a=I_frame_interval:"); sptr = skip_whitespace(sptr, line_end_ptr); if (sptr >= line_end_ptr) { PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=I_frame_interval line format")); return SDP_BAD_MEDIA_FRAME_INTERVAL; } uint32 ifi; if (PV_atoi(sptr, 'd', (line_end_ptr - sptr), ifi) == true)((m4v_mediaInfo *)m4Video)->setIFrameInterval(ifi); } 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, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - Bad payload number")); return SDP_BAD_MEDIA_FMTP; } else { int p; if (!m4Video->lookupPayloadNumber(payloadNumber, p)) { fmtp_cnt--; break; } } M4vPayloadSpecificInfoType* payloadPtr = (M4vPayloadSpecificInfoType*)m4Video->getPayloadSpecificInfoTypePtr(payloadNumber); if (payloadPtr == NULL) { PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - payload pointer not found for payload")); return SDP_PAYLOAD_MISMATCH; } PVMF_SDP_PARSER_LOGINFO((0, "SDPM4VMediaInfoParser::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(VOLLength); OsclRefCounterSA< SDPAllocDestructDealloc<uint8> > *refcnt = new OsclRefCounterSA< SDPAllocDestructDealloc<uint8> >(mptr); OsclSharedPtr<uint8> VOLPtr(mptr, refcnt); temp += oscl_strlen("config="); temp = skip_whitespace(temp, line_end_ptr); if (temp >= line_end_ptr) { PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - Bad config field")); return SDP_BAD_MEDIA_FMTP; } VOLLength = (int)(tmp_end_line - temp) / 2; int idx = 0; for (idx = 0; idx < VOLLength; idx++) { uint32 val; //Set this value in the vol header array if (PV_atoi((temp + 2*idx), 'x', 2 , val) == false) { PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - Bad config field")); return SDP_BAD_MEDIA_FMTP; } *(VOLPtr + idx) = (uint8)val; } payloadPtr->setVOLHeader(VOLPtr); payloadPtr->setVOLHeaderSize(VOLLength); payloadPtr->setDecoderSpecificInfo(VOLPtr); payloadPtr->setDecoderSpecificInfoSize(VOLLength); } if (!oscl_strncmp(temp, "profile-level-id=", oscl_strlen("profile-level-id="))) { temp += oscl_strlen("profile-level-id="); temp = skip_whitespace(temp, line_end_ptr); if (temp > line_end_ptr) { PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - Bad profile-level-id field")); return SDP_BAD_MEDIA_FMTP; } uint32 pl; if (PV_atoi(temp, 'd', tmp_end_line - temp , pl) == true) payloadPtr->setProfileLevelID(pl); } if (!oscl_strncmp(temp, "framesize=", oscl_strlen("framesize="))) { temp += oscl_strlen("framesize="); temp = skip_whitespace(temp, tmp_end_line); framesize_found_in_fmtp = true; if (temp > tmp_end_line) { PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - Bad framesize field")); return SDP_BAD_MEDIA_FMTP; } const char *end = NULL; int idx = 0; for (idx = 0; idx < (tmp_end_line - temp); idx++) { if (temp[idx] == '-') { end = temp + idx; } } if (end == NULL) { PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - framesize width info missing")); return SDP_MISSING_MEDIA_DESCRIPTION; } uint32 width; if (PV_atoi(temp, 'd', (end - temp), width) == true) payloadPtr->setFrameWidth(width); temp = end + 1; temp = skip_whitespace(temp, tmp_end_line); if (temp > tmp_end_line) { PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - framesize height info missing")); return SDP_BAD_MEDIA_FMTP; } uint32 height; if (PV_atoi(temp, 'd', tmp_end_line - temp, height) == true) payloadPtr->setFrameHeight(height); } 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, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - Bad decode_buf field")); return SDP_BAD_MEDIA_FMTP; } uint32 dec; if (PV_atoi(temp, 'd', tmp_end_line - temp, dec) == true) payloadPtr->setMaxBufferSize(dec); } 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, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format")); return SDP_BAD_MEDIA_FMTP; } } } } StrPtrLen fmsize("a=framesize:"); if (!oscl_strncmp(line_start_ptr, fmsize.c_str(), fmsize.length())) { uint32 width, height; const char *sptr = line_start_ptr + fmsize.length(); const char *eptr = skip_to_whitespace(sptr, line_end_ptr); if (sptr > eptr) { PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=framesize line format")); return SDP_BAD_MEDIA_FRAMESIZE; } uint32 payloadNo; if (PV_atoi(sptr, 'd', (eptr - sptr), payloadNo)) { int p; if (!((m4v_mediaInfo *)m4Video)->lookupPayloadNumber(payloadNo, p)) break; } else { PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=framesize line format - Bad payload number")); return SDP_BAD_MEDIA_FRAMESIZE; } M4vPayloadSpecificInfoType* payloadPtr2 = (M4vPayloadSpecificInfoType*)m4Video->getPayloadSpecificInfoTypePtr(payloadNo); if (payloadPtr2 == NULL) { PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=framesize line format - payload pointer not found for payload")); return SDP_PAYLOAD_MISMATCH; } sptr = eptr; sptr = skip_whitespace(sptr , line_end_ptr); for (; *eptr != '-' ; ++eptr); if (!PV_atoi(sptr, 'd', eptr - sptr, width)) { PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=framesize line format")); return SDP_BAD_MEDIA_FRAMESIZE; } eptr = eptr + 1; sptr = eptr; if (sptr > line_end_ptr) return SDP_BAD_MEDIA_FRAMESIZE; eptr = skip_to_line_term(sptr, line_end_ptr); if (!PV_atoi(sptr, 'd', eptr - sptr, height)) return SDP_BAD_MEDIA_FRAMESIZE; if (framesize_found_in_fmtp) { if ((int)width != payloadPtr2->getFrameWidth() || (int)height != payloadPtr2->getFrameHeight()) { return SDP_BAD_MEDIA_FRAMESIZE; } } else { payloadPtr2->setFrameWidth(width); payloadPtr2->setFrameHeight(height); } } } 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, m4Video, 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, m4Video, alt_id); if (status != SDP_SUCCESS) return SDP_BAD_MEDIA_ALT_ID; } if (m4Video->getCFieldStatus() || session->getCFieldStatus()) { //if sample rate is zero override with defaults Oscl_Vector<PayloadSpecificInfoTypeBase*, SDPParserAlloc> payloadSpecificInfoVector = m4Video->getPayloadSpecificInfoVector(); for (int ii = 0; ii < (int)payloadSpecificInfoVector.size(); ii++) { if (payloadSpecificInfoVector[ii]->getSampleRate() == 0) { payloadSpecificInfoVector[ii]->sampleRate = PVMF_SDP_DEFAULT_MPEG4_VIDEO_SAMPLE_RATE; } } return SDP_SUCCESS; } else { PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - No C field present")); return SDP_FAILURE_NO_C_FIELD; } } }