| /* ------------------------------------------------------------------ |
| * 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 "sdp_parser.h" |
| #include "sdp_mediaparser_registry.h" |
| #include "oscl_string_utils.h" |
| #include "oscl_string_containers.h" |
| #include "oscl_str_ptr_len.h" |
| #include "base_media_info_parser.h" |
| #include "aac_media_info_parser.h" |
| #include "amr_media_info_parser.h" |
| #include "h263_media_info_parser.h" |
| #include "m4v_media_info_parser.h" |
| #include "still_image_media_info_parser.h" |
| #include "pcma_media_info_parser.h" |
| #include "pcmu_media_info_parser.h" |
| #include "oscl_vector.h" |
| #include "oscl_dll.h" |
| |
| OSCL_DLL_ENTRY_POINT_DEFAULT() |
| struct mime_payload_pair |
| { |
| OsclMemoryFragment mime; |
| Oscl_Vector<int, SDPParserAlloc> payload_no; |
| }; |
| |
| OSCL_EXPORT_REF SDP_Parser::SDP_Parser(SDPMediaParserRegistry*& regTable, bool sipSdp): |
| iLogger(NULL), |
| _pSDPMediaParserRegistry(regTable), |
| mediaArrayIndex(0), |
| applicationFlag(false), |
| isSipSdp(sipSdp) |
| { |
| iLogger = PVLogger::GetLoggerObject("SDP_Parser"); |
| } |
| |
| |
| OSCL_EXPORT_REF SDP_Parser::~SDP_Parser() |
| { |
| } |
| |
| bool SDP_Parser::parse_rtpmap(const char *start, const char *end, int& rtp_payload, |
| OsclMemoryFragment& encoding_name) |
| { |
| const int len_of_rtpmap = 9; |
| |
| // grab the endpoints |
| const char *sptr = start + len_of_rtpmap; |
| const char *eptr; |
| |
| // skip to the first whitespace character |
| eptr = skip_to_whitespace(sptr, end); |
| if (eptr < sptr) |
| { |
| return false; |
| } |
| uint32 rtpPayload; |
| if (PV_atoi(sptr, 'd', (eptr - sptr), rtpPayload) == false) |
| { |
| return false; |
| } |
| rtp_payload = (int)rtpPayload; |
| |
| // now get the encoding name |
| sptr = skip_whitespace(eptr, end); |
| if (sptr >= end) |
| { |
| return false; |
| } |
| |
| // now skip to end of the encoding name |
| for (eptr = sptr; eptr < end && |
| (*eptr != ' ' && *eptr != '\t' && *eptr != '/'); |
| ++eptr); |
| |
| if (eptr >= end) |
| { |
| return false; |
| } |
| |
| encoding_name.ptr = (void *) sptr; |
| encoding_name.len = eptr - sptr; |
| |
| return true; |
| } |
| |
| |
| int SDP_Parser::validate_media_line(const char *start, const char *end, Oscl_Vector<int, SDPParserAlloc>& payload_type, uint32& portNumber) |
| { |
| int len; |
| const char *sptr, *eptr; |
| |
| sptr = start + 2; // start after the "m=" |
| // skip to end of media type |
| eptr = skip_to_whitespace(sptr, end); |
| if (eptr >= end) |
| { |
| return 0; |
| } |
| |
| |
| len = eptr - sptr; |
| // make sure type is supported |
| if (!oscl_CIstrncmp(sptr, "audio", len) || !oscl_CIstrncmp(sptr, "video", len) || |
| !oscl_CIstrncmp(sptr, "application", len)) |
| { |
| // the type is supported |
| // make sure there is only one payload type in the format list |
| |
| // skip to start of port number |
| sptr = skip_whitespace(eptr, end); |
| if (sptr >= end) |
| { |
| return 0; |
| } |
| |
| // skip to end of port number |
| eptr = skip_to_whitespace(sptr, end); |
| if (eptr <= sptr) |
| { |
| return 0; |
| } |
| |
| const char *tmp_end_ptr = sptr; |
| const char SDP_FWD_SLASH[] = "/"; |
| |
| OSCL_HeapString<SDPParserAlloc> restOfLine(tmp_end_ptr, eptr - tmp_end_ptr); |
| const char *slash = oscl_strstr(restOfLine.get_cstr(), SDP_FWD_SLASH); |
| |
| if (slash == NULL) |
| { |
| // Get the port number |
| if (PV_atoi(sptr, 'd', (eptr - sptr), portNumber) == false) |
| { |
| return 0; |
| } |
| } |
| else |
| { |
| // Get the port number |
| if (PV_atoi(restOfLine.get_cstr(), 'd', (slash - restOfLine.get_cstr()), portNumber) == false) |
| { |
| return 0; |
| } |
| } |
| |
| // skip to start of transport |
| sptr = skip_whitespace(eptr, end); |
| if (sptr >= end) |
| { |
| return 0; |
| } |
| |
| // skip to end of transport |
| eptr = skip_to_whitespace(sptr, end); |
| if (eptr <= sptr) |
| { |
| return 0; |
| } |
| |
| // skip to start of format list |
| sptr = skip_whitespace(eptr, end); |
| if (sptr >= end) |
| { |
| return 0; |
| } |
| |
| // skip to end of first payload arg |
| eptr = skip_to_whitespace(sptr, end); |
| if (eptr <= sptr) |
| { |
| return 0; |
| } |
| |
| // record the payload type for non-application m= lines |
| if (oscl_strncmp(start + 2, "application", len)) |
| { |
| uint32 payloadType; |
| |
| while (sptr < end) |
| { |
| if (PV_atoi(sptr, 'd', (eptr - sptr), payloadType) == false) |
| { |
| return 0; |
| } |
| |
| payload_type.push_back(payloadType); |
| |
| sptr = skip_to_whitespace(sptr, end); |
| sptr = skip_whitespace_and_line_term(eptr, end); |
| eptr = skip_whitespace_and_line_term(eptr, end); |
| eptr = skip_to_whitespace(eptr, end); |
| } |
| } |
| else |
| { |
| uint32 len = OSCL_MIN((uint32)(eptr - start), oscl_strlen("IMAGE")); |
| if (!oscl_strncmp(start, "IMAGE", len)) |
| { |
| applicationFlag = true; |
| } |
| else //don't support this media. so skip the section |
| return 0; |
| } |
| |
| if (sptr < end) |
| { |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| return 0; |
| |
| } |
| |
| OSCL_EXPORT_REF |
| SDP_ERROR_CODE SDP_Parser::parseSDP(const char *sdpText, int text_length, SDPInfo *sdp) |
| { |
| int index = 0, sdpIndex = 0; |
| |
| const char *end_ptr = sdpText + text_length ; // Point just beyond the end |
| const char *section_start_ptr; |
| const char *section_end_ptr; |
| const char *line_start_ptr, *line_end_ptr; |
| bool session_info_parsed = false; |
| |
| /**************************************************************************/ |
| |
| // The purpose of this outer loop is to partition the SDP into different |
| // sections to be passed off to session-level parsers or media-level parsers. |
| // We just need to find the boundaries and pass the appropriate sections |
| // of code to the subparsers. |
| |
| sdpIndex = 0; |
| index = 0; |
| |
| // these track whether media and session-level sections have already |
| // been found |
| int media_sections_found = 0; |
| int session_section_found = 0; |
| |
| // skip any leading whitespace including line terminators |
| section_start_ptr = skip_whitespace_and_line_term(sdpText, end_ptr); |
| |
| while ((section_start_ptr - sdpText) < text_length) |
| { |
| if (!get_next_line(section_start_ptr, end_ptr, |
| line_start_ptr, line_end_ptr)) |
| { |
| break; |
| } |
| |
| // figure out the type of section |
| if (!oscl_strncmp(line_start_ptr, "v=", 2)) |
| { |
| // this is the session-level |
| if (media_sections_found || session_section_found) |
| { |
| // there were already media sections or already a session-level section |
| // so a session-level section at this point is not allowed. |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Duplicate Session Sections")); |
| return SDP_BAD_FORMAT; |
| } |
| |
| section_end_ptr = line_end_ptr; |
| |
| // record that the session-level section has been found |
| session_section_found = 1; |
| |
| while (get_next_line(section_end_ptr, end_ptr, |
| line_start_ptr, line_end_ptr)) |
| { |
| // check if this is the start of another section |
| if (!oscl_strncmp(line_start_ptr, "v=", 2) || |
| !oscl_strncmp(line_start_ptr, "m=", 2)) |
| { |
| break; |
| } |
| section_end_ptr = line_end_ptr; |
| } |
| |
| |
| OsclMemoryFragment session_frag; |
| session_frag.ptr = (void *)section_start_ptr; |
| session_frag.len = section_end_ptr - section_start_ptr; |
| |
| SDP_ERROR_CODE retval = |
| parseSDPSessionInfo(section_start_ptr, |
| section_end_ptr - section_start_ptr, |
| sdp); |
| if (retval != SDP_SUCCESS) |
| { |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - parseSDPSessionInfo Failed=%d", retval)); |
| return retval; |
| } |
| else |
| { |
| session_info_parsed = true; |
| } |
| } |
| else if (!oscl_strncmp(line_start_ptr, "m=", 2)) |
| { |
| |
| // now look for the end of the section |
| section_end_ptr = line_end_ptr; |
| bool supported_media = true; |
| |
| ++media_sections_found; |
| sdp->setSegmentCount(media_sections_found); |
| |
| /* SUPPORTING MULTIPLE PAYLOAD TYPE PER MEDIA NOW */ |
| // check to see how many payload types are present |
| Oscl_Vector<int, SDPParserAlloc> payload_type; |
| Oscl_Vector<int, SDPParserAlloc> rtpmap_pt; |
| Oscl_Vector<OsclMemoryFragment, SDPParserAlloc> encoding_name_vector; |
| |
| uint32 portNumber = 0; |
| if (!validate_media_line(line_start_ptr, line_end_ptr, payload_type, portNumber)) |
| { |
| // skip this section |
| supported_media = false; |
| } |
| else |
| { |
| PVMF_SDP_PARSER_LOGINFO((0, "SDP_Parser::parseSDP - Validated MediaSection")); |
| } |
| |
| int rtpmap_lines = 0; |
| |
| // get the next line |
| OsclMemoryFragment encoding_name; |
| encoding_name.ptr = NULL; |
| encoding_name.len = 0; |
| |
| Oscl_Vector<int, SDPParserAlloc> AltId; |
| while (get_next_line(section_end_ptr, end_ptr, line_start_ptr, line_end_ptr)) |
| { |
| // check if this is the start of another section |
| if (!oscl_strncmp(line_start_ptr, "v=", 2) || |
| !oscl_strncmp(line_start_ptr, "m=", 2)) |
| { |
| break; |
| } |
| if (supported_media && (applicationFlag == false)) |
| { |
| // check for lines which will give the media type |
| // so the parser can be allocated. Simply look for |
| // the "a=rtpmap" lines which contain the MIME type. |
| StrPtrLen rtpmap_str("a=rtpmap:"); |
| if (!oscl_strncmp(line_start_ptr, rtpmap_str.c_str(), rtpmap_str.length())) |
| { |
| ++rtpmap_lines; |
| int rtpmap_cu; |
| // get encoding name |
| if (!parse_rtpmap(line_start_ptr, line_end_ptr, rtpmap_cu, encoding_name)) |
| { |
| // invalid format |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - parse_rtpmap Failed")); |
| return SDP_BAD_MEDIA_FORMAT; |
| } |
| rtpmap_pt.push_back(rtpmap_cu); |
| encoding_name_vector.push_back(encoding_name); |
| OSCL_StackString<15> mime((const char*)(encoding_name.ptr), encoding_name.len); |
| PVMF_SDP_PARSER_LOGINFO((0, "SDP_Parser::parseSDP - a=rtpmap mime=%s", mime.get_cstr())); |
| } |
| StrPtrLen alt_def("a=alt-default-id:"); |
| if (!oscl_strncmp(line_start_ptr, alt_def.c_str(), alt_def.length())) |
| { |
| uint32 id; |
| const char *sptr = line_start_ptr + alt_def.length(); |
| sptr = skip_whitespace(sptr, line_end_ptr); |
| if (!PV_atoi(sptr, 'd', line_end_ptr - sptr, id)) |
| { |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing a=alt-default-id: Failed")); |
| return SDP_BAD_MEDIA_ALT_ID; |
| } |
| AltId.push_back(id); |
| } |
| StrPtrLen alt_id("a=alt:"); |
| if (!oscl_strncmp(line_start_ptr, alt_id.c_str(), alt_id.length())) |
| { |
| uint32 id; |
| const char *sptr = line_start_ptr + alt_id.length(); |
| sptr = skip_whitespace(sptr, line_end_ptr); |
| const char *eptr = sptr; |
| for (; *eptr != ':'; eptr++); |
| if (!PV_atoi(sptr, 'd', eptr - sptr, id)) |
| { |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing a=alt: Failed")); |
| return SDP_BAD_MEDIA_ALT_ID; |
| } |
| if (AltId.back() != (int)id) |
| AltId.push_back(id); |
| } |
| |
| // fmtp and framesize payload check is provided below |
| // this is done to make sure that the payload coming in these fields |
| // is one of the payloads in the m= segment |
| StrPtrLen fmtp("a=fmtp:"); |
| if (!oscl_strncmp(line_start_ptr, fmtp.c_str(), fmtp.length())) |
| { |
| uint32 payload; |
| const char *sptr = line_start_ptr + fmtp.length(); |
| sptr = skip_whitespace(sptr, line_end_ptr); |
| const char* eptr = skip_to_whitespace(sptr, line_end_ptr); |
| if (!PV_atoi(sptr, 'd', eptr - sptr, payload)) |
| { |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing a=fmtp: Failed")); |
| return SDP_BAD_MEDIA_FORMAT; |
| } |
| // The format is proper match the payload with payloads in m= segment |
| bool matched = false; |
| for (uint32 ii = 0; ii < payload_type.size(); ii++) |
| { |
| if (payload == (uint32)payload_type[ii]) |
| { |
| matched = true; |
| break; |
| } |
| } |
| if (!matched) |
| { |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Payload Mismatch in fmtp line")); |
| return SDP_PAYLOAD_MISMATCH; |
| } |
| } |
| StrPtrLen framesize("a=framesize:"); |
| if (!oscl_strncmp(line_start_ptr, framesize.c_str(), framesize.length())) |
| { |
| uint32 payload; |
| const char *sptr = line_start_ptr + framesize.length(); |
| sptr = skip_whitespace(sptr, line_end_ptr); |
| const char* eptr = skip_to_whitespace(sptr, line_end_ptr); |
| if (!PV_atoi(sptr, 'd', eptr - sptr, payload)) |
| { |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing a=framesize: Failed")); |
| return SDP_BAD_MEDIA_FORMAT; |
| } |
| // The format is proper match the payload with payloads in m= segment |
| bool matched = false; |
| for (uint32 ii = 0; ii < payload_type.size(); ii++) |
| { |
| if (payload == (uint32)payload_type[ii]) |
| { |
| matched = true; |
| break; |
| } |
| } |
| if (!matched) |
| { |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Payload Mismatch in a=framesize: line")); |
| return SDP_PAYLOAD_MISMATCH; |
| } |
| } |
| |
| } // end if media is supported |
| else |
| { |
| PVMF_SDP_PARSER_LOGINFO((0, "SDP_Parser::parseSDP - Skipping over an entire m= section")); |
| } |
| |
| section_end_ptr = line_end_ptr; |
| } // end loop over the entire media section |
| |
| |
| // The checking for rtpmap vs payloads is not required if the port number is 0 in case it is a sip sdp |
| bool check_for_rtpmap = true; |
| if (isSipSdp && portNumber == 0) |
| { |
| check_for_rtpmap = false; |
| } |
| |
| // Checking for rtpmap with the payloads |
| if (supported_media && check_for_rtpmap) |
| { |
| // Validate the payload type and rtpmap if required |
| int static_payload_count = 0; |
| int ii = 0; |
| for (; ii < (int)payload_type.size(); ii++) |
| { |
| // If any payload_type is in static range we do not care |
| // for the rtpmap field. We will process for this static payload type sdp |
| // the dynamic payload type if any will be ignored if it's rtpmap |
| // is missing |
| if ((payload_type[ii] >= FIRST_STATIC_PAYLOAD) && |
| (payload_type[ii] <= LAST_STATIC_PAYLOAD)) |
| { |
| PVMF_SDP_PARSER_LOGINFO((0, "SDP_Parser::parseSDP - Static Payload =%d", payload_type[ii])); |
| static_payload_count++; |
| } |
| } |
| if (static_payload_count == 0) |
| { |
| // The payload type present are all in the dynamic range |
| if (rtpmap_pt.size() != payload_type.size()) |
| { |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Mismatch between number of payloads and rtpmap lines")); |
| return SDP_BAD_MEDIA_FORMAT; |
| } |
| for (int ii = 0; ii < (int)rtpmap_pt.size(); ii++) |
| { |
| if (rtpmap_pt[ii] != payload_type[ii]) |
| { |
| // this is an error |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Incorrect payload number in rtpmap line")); |
| return SDP_PAYLOAD_MISMATCH; |
| } |
| } |
| } |
| else if (static_payload_count >= 1) |
| { |
| // All of the payloads can either be static or one of them |
| // for every dynamic payload there should be matching rtpmap field |
| if (rtpmap_pt.size() != (payload_type.size() - static_payload_count)) |
| { |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Mismatch between number of payloads and rtpmap lines")); |
| return SDP_BAD_MEDIA_FORMAT; |
| } |
| for (uint32 rtpmap_count = 0; rtpmap_count < rtpmap_pt.size(); rtpmap_count++) |
| { |
| bool match_found = false; |
| for (int jj = 0; jj < (int)payload_type.size(); jj++) |
| { |
| if (rtpmap_pt[rtpmap_count] == payload_type[jj]) |
| { |
| match_found = true; |
| break; |
| } |
| } |
| if (match_found == false) |
| { |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - No matching rtpmap line")); |
| // this is an error |
| return SDP_PAYLOAD_MISMATCH; |
| } |
| } |
| } |
| } |
| |
| if (session_info_parsed == false) |
| { |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Missing Session Section")); |
| return SDP_BAD_FORMAT; |
| } |
| |
| if (supported_media) |
| { |
| StrPtrLen image("X-MP4V-IMAGE"); |
| if (applicationFlag == true) |
| { |
| if (rtpmap_lines == 0) |
| { |
| rtpmap_lines++; |
| encoding_name.ptr = (void *) image.c_str(); |
| encoding_name.len = image.length(); |
| applicationFlag = false; |
| encoding_name_vector.push_back(encoding_name); |
| } |
| } |
| |
| // Compose all media encoding names and put them in one vector |
| // this will carry all encoding names including static and dynamic PT |
| StrPtrLen pcma(PVMF_MIME_PCMA); |
| StrPtrLen pcmu(PVMF_MIME_PCMU); |
| StrPtrLen amr("AMR"); |
| Oscl_Vector<OsclMemoryFragment, SDPParserAlloc> all_media_encoding_names; |
| uint32 ii = 0; |
| uint32 jj = 0; |
| for (; ii < payload_type.size(); ii++) |
| { |
| if (payload_type[ii] == PVMF_PCMU) |
| { |
| rtpmap_lines++; |
| encoding_name.ptr = (void *) pcmu.c_str(); |
| encoding_name.len = pcmu.length(); |
| } |
| else if (payload_type[ii] == PVMF_PCMA) |
| { |
| rtpmap_lines++; |
| encoding_name.ptr = (void *) pcma.c_str(); |
| encoding_name.len = pcma.length(); |
| } |
| else if (check_for_rtpmap == false) |
| { |
| // This means that the port is 0 and they payload is in dynamic range |
| // rtpmap field is not present. |
| // To map it internally let's put it under PCMU again |
| rtpmap_lines++; |
| encoding_name.ptr = (void *) pcmu.c_str(); |
| encoding_name.len = pcmu.length(); |
| } |
| else |
| { |
| // All other payload encoding names are already present in the |
| // encoding_name_vector. |
| if (jj < encoding_name_vector.size()) |
| { |
| encoding_name = encoding_name_vector[jj]; |
| jj++; |
| } |
| } |
| all_media_encoding_names.push_back(encoding_name); |
| } |
| |
| // compose all the above information in the following format |
| // Any Mime type coming repeatedly with different payload numbers |
| // Then club them together |
| Oscl_Vector<mime_payload_pair, SDPParserAlloc> mime_payload_pair_vector; |
| |
| for (uint32 ll = 0; ll < payload_type.size(); ll++) |
| { |
| if (check_for_rtpmap == true) |
| { |
| bool matched = false; |
| uint32 ii = 0; |
| for (; ii < mime_payload_pair_vector.size(); ii++) |
| { |
| if (oscl_strncmp((char*)mime_payload_pair_vector[ii].mime.ptr, |
| (char*)all_media_encoding_names[ll].ptr, |
| all_media_encoding_names[ll].len) == 0) |
| { |
| matched = true; |
| break; |
| } |
| } |
| if (matched) |
| { |
| mime_payload_pair_vector[ii].payload_no.push_back(payload_type[ll]); |
| } |
| else |
| { |
| mime_payload_pair mpp; |
| mpp.payload_no.push_back(payload_type[ll]); |
| mpp.mime.len = all_media_encoding_names[ll].len; |
| mpp.mime.ptr = all_media_encoding_names[ll].ptr; |
| mime_payload_pair_vector.push_back(mpp); |
| } |
| } |
| else |
| { |
| // It is a sip sdp with port = 0. Hence do not make specific checks |
| mime_payload_pair mpp; |
| mpp.payload_no.push_back(payload_type[ll]); |
| mpp.mime.len = all_media_encoding_names[ll].len; |
| mpp.mime.ptr = all_media_encoding_names[ll].ptr; |
| mime_payload_pair_vector.push_back(mpp); |
| } |
| |
| } |
| |
| if (rtpmap_lines >= 1) |
| { |
| SDPMediaParserFactory *mediaParserFactory; |
| SDPBaseMediaInfoParser *mediaParser; |
| SDP_ERROR_CODE retval; |
| |
| for (uint32 kk = 0; kk < mime_payload_pair_vector.size(); kk++) |
| { |
| encoding_name = mime_payload_pair_vector[kk].mime; |
| if ((mediaParserFactory = |
| _pSDPMediaParserRegistry->lookupSDPMediaParserFactory(encoding_name)) != NULL) |
| { |
| mediaParser = mediaParserFactory->createSDPMediaParserInstance(); |
| if (mediaParser == NULL) |
| { |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Unable to create media parser")); |
| return SDP_FAILURE; |
| } |
| if (AltId.size() > 0) |
| { |
| int alt_id; |
| bool alt_def_id = false; |
| for (int ss = 0; ss < (int)AltId.size(); ss++) |
| { |
| if (ss == 0) alt_def_id = true; |
| else alt_def_id = false; |
| |
| alt_id = AltId[ss]; |
| |
| if ((retval = mediaParser->parseMediaInfo(section_start_ptr, section_end_ptr - section_start_ptr, sdp, mime_payload_pair_vector[kk].payload_no, isSipSdp, alt_id, alt_def_id)) != SDP_SUCCESS) |
| { |
| OSCL_StackString<8> mime((const char*)(encoding_name.ptr), encoding_name.len); |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing m= section failed, mime=%s", mime.get_cstr())); |
| OSCL_DELETE((mediaParser)); |
| sdp->freeLastMediaInfoObject(); |
| return retval; |
| } |
| |
| } |
| } |
| else |
| { |
| if ((retval = mediaParser->parseMediaInfo(section_start_ptr, section_end_ptr - section_start_ptr, sdp, mime_payload_pair_vector[kk].payload_no, isSipSdp)) != SDP_SUCCESS) |
| { |
| OSCL_StackString<8> mime((const char*)(encoding_name.ptr), encoding_name.len); |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing m= section failed, mime=%s", mime.get_cstr())); |
| OSCL_DELETE((mediaParser)); |
| sdp->freeLastMediaInfoObject(); |
| return retval; |
| } |
| } |
| sdp->IncrementAlternateMediaInfoVectorIndex(); |
| OSCL_DELETE((mediaParser)); |
| } |
| mediaParser = NULL; |
| } // End of for |
| } |
| if (rtpmap_lines == 0) // no rtpmap found in media |
| { |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing m= section failed, No rtpmap line")); |
| return SDP_BAD_MEDIA_MISSING_RTPMAP; |
| } |
| } |
| } // end this is a media section |
| else |
| { |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Unrecognized Syntax")); |
| // unknown section type -- this is an error |
| return SDP_FAILURE; |
| } |
| |
| section_start_ptr = skip_whitespace_and_line_term(section_end_ptr, end_ptr); |
| |
| } |
| { |
| //for SDP which doesn't have session level range, set the session level range |
| //to be the MAX of media ranges. |
| if (NULL == sdp->getSessionInfo()) |
| { |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Missing Session Info")); |
| return SDP_BAD_FORMAT; |
| } |
| RtspRangeType *mySdpRange = ((RtspRangeType *)sdp->getSessionInfo()->getRange()); |
| if (NULL == mySdpRange) |
| { |
| PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Unable to retrieve session range")); |
| return SDP_BAD_FORMAT; |
| } |
| if (mySdpRange->format == RtspRangeType::INVALID_RANGE) |
| { |
| PVMF_SDP_PARSER_LOGINFO((0, "SDP_Parser::parseSDP - No Valid Session Range - Setting it to Max of all media ranges")); |
| for (int32 i = sdp->getNumMediaObjects() - 1; i >= 0; i--) |
| { |
| Oscl_Vector<mediaInfo*, SDPParserAlloc> mediaInfoVec = |
| sdp->getMediaInfo(i); |
| for (uint32 j = 0; j < mediaInfoVec.size(); j++) |
| { |
| mediaInfo* mInfo = mediaInfoVec[j]; |
| if (mInfo == NULL) |
| { |
| continue; |
| } |
| const RtspRangeType *mInfoSdpRange = mInfo->getRtspRange(); |
| if (NULL == mInfoSdpRange) |
| { |
| continue; |
| } |
| if (mInfoSdpRange->format != RtspRangeType::NPT_RANGE) |
| { |
| continue; |
| } |
| if (mySdpRange->format == RtspRangeType::INVALID_RANGE) |
| { |
| *mySdpRange = *mInfoSdpRange; |
| } |
| if (!mInfoSdpRange->end_is_set) |
| {//live streaming |
| *mySdpRange = *mInfoSdpRange; |
| mySdpRange->start_is_set = true;//just to make sure |
| mySdpRange->npt_start.npt_format = NptTimeFormat::NOW; |
| return SDP_SUCCESS; |
| } |
| if (mInfoSdpRange->npt_start.npt_format == NptTimeFormat::NPT_SEC) |
| { |
| if (mInfoSdpRange->npt_start.npt_sec.sec < mySdpRange->npt_start.npt_sec.sec) |
| { |
| mySdpRange->npt_start.npt_sec = mInfoSdpRange->npt_start.npt_sec; |
| } |
| else if ((mInfoSdpRange->npt_start.npt_sec.sec == mySdpRange->npt_start.npt_sec.sec) |
| && ((mInfoSdpRange->npt_start.npt_sec.milli_sec < mySdpRange->npt_start.npt_sec.milli_sec))) |
| { |
| mySdpRange->npt_start.npt_sec = mInfoSdpRange->npt_start.npt_sec; |
| } |
| } |
| if (mInfoSdpRange->npt_end.npt_format == NptTimeFormat::NPT_SEC) |
| { |
| if (mInfoSdpRange->npt_end.npt_sec.sec > mySdpRange->npt_end.npt_sec.sec) |
| { |
| mySdpRange->npt_end.npt_sec = mInfoSdpRange->npt_end.npt_sec; |
| } |
| else if ((mInfoSdpRange->npt_end.npt_sec.sec == mySdpRange->npt_end.npt_sec.sec) |
| && ((mInfoSdpRange->npt_end.npt_sec.milli_sec > mySdpRange->npt_end.npt_sec.milli_sec))) |
| { |
| mySdpRange->npt_end.npt_sec = mInfoSdpRange->npt_end.npt_sec; |
| } |
| } |
| } |
| } |
| } |
| } |
| return SDP_SUCCESS; |
| } |
| |
| OSCL_EXPORT_REF SDP_ERROR_CODE |
| SDP_Parser::parseSDPDownload(const char *sdpText, |
| int length, |
| SDPInfo *sdp, |
| movieInfo *mv) |
| { |
| SDP_ERROR_CODE retval = parseSDP(sdpText, length, sdp); |
| if (retval != SDP_SUCCESS) |
| { |
| mv->trackCount = 0; |
| mv->movieName[0] = '\0'; |
| mv->creationDate[0] = '\0'; |
| return retval; |
| } |
| else |
| { |
| /*Get Movie name*/ |
| int len = oscl_strlen(sdp->getSessionInfo()->getSessionName()); |
| if (len >= MAX_STRING_LEN) |
| { |
| oscl_strncpy(mv->movieName, sdp->getSessionInfo()->getSessionName(), (MAX_STRING_LEN - 1)); |
| mv->movieName[MAX_STRING_LEN-1] = '\0'; |
| } |
| else |
| { |
| oscl_strncpy(mv->movieName, sdp->getSessionInfo()->getSessionName(), len); |
| mv->movieName[len] = '\0'; |
| } |
| |
| /*Get creation date*/ |
| len = oscl_strlen(sdp->getSessionInfo()->getCreationDate()); |
| if (len >= MAX_STRING_LEN) |
| { |
| oscl_strncpy(mv->creationDate, sdp->getSessionInfo()->getCreationDate(), (MAX_STRING_LEN - 1)); |
| mv->creationDate[MAX_STRING_LEN-1] = '\0'; |
| } |
| else |
| { |
| oscl_strncpy(mv->creationDate, sdp->getSessionInfo()->getCreationDate(), len); |
| mv->creationDate[len] = '\0'; |
| } |
| |
| /*Get number of tracks*/ |
| mv->trackCount = sdp->getNumMediaObjects(); |
| |
| /*Get start stop times*/ |
| convertToMilliSec(*sdp->getSessionInfo()->getRange(), mv->duration.startTime, mv->duration.stopTime); |
| |
| /*Get MIMEType and other track info*/ |
| for (int ii = 0; ii < mv->trackCount; ii++) |
| { |
| Oscl_Vector<mediaInfo*, SDPParserAlloc> mediaInfoVec = |
| sdp->getMediaInfo(ii); |
| |
| /* |
| * There would only be one element in this vector |
| * for fast track download content. |
| */ |
| mediaInfo* minfo = mediaInfoVec[0]; |
| |
| mv->TrackArray[ii].bitrate = minfo->getBitrate(); |
| len = oscl_strlen(minfo->getMIMEType()); |
| if (len >= MAX_STRING_LEN) |
| { |
| oscl_strncpy(mv->TrackArray[ii].codec_type, |
| minfo->getMIMEType(), |
| (MAX_STRING_LEN - 1)); |
| mv->TrackArray[ii].codec_type[MAX_STRING_LEN-1] = '\0'; |
| } |
| else |
| { |
| oscl_strncpy(mv->TrackArray[ii].codec_type, |
| minfo->getMIMEType(), |
| len); |
| mv->TrackArray[ii].codec_type[len] = '\0'; |
| } |
| const char *trackID = minfo->getControlURL(); |
| int track = 0; |
| if (trackID != NULL) |
| { |
| const char *locateID = oscl_strstr(trackID, "="); |
| if (locateID != NULL) |
| { |
| locateID += 1; |
| uint32 atoi_tmp; |
| PV_atoi(locateID, 'd', atoi_tmp); |
| track = atoi_tmp; |
| } |
| } |
| mv->TrackArray[ii].trackID = track; |
| } |
| } |
| return SDP_SUCCESS; |
| } |
| |
| |
| int |
| SDP_Parser::convertToMilliSec(RtspRangeType range , int &startTime, int &stopTime) |
| { |
| switch (range.format) |
| { |
| case RtspRangeType::NPT_RANGE: |
| { |
| if (range.start_is_set) |
| { |
| switch (range.npt_start.npt_format) |
| { |
| case NptTimeFormat::NOW: |
| { |
| startTime = 0; |
| } |
| break; |
| case NptTimeFormat::NPT_SEC: |
| { |
| startTime = (int)(1000 * ((float)range.npt_start.npt_sec.sec + range.npt_start.npt_sec.milli_sec)); |
| } |
| break; |
| case NptTimeFormat::NPT_HHMMSS: |
| { |
| startTime = 3600000 * range.npt_start.npt_hhmmss.hours + 60000 * range.npt_start.npt_hhmmss.min + 1000 * range.npt_start.npt_hhmmss.sec + (int)(10 * range.npt_start.npt_hhmmss.frac_sec); |
| } |
| break; |
| } |
| } |
| else |
| { |
| startTime = 0; |
| } |
| if (range.end_is_set) |
| { |
| switch (range.npt_end.npt_format) |
| { |
| case NptTimeFormat::NOW: |
| { |
| stopTime = 0; |
| } |
| break; |
| case NptTimeFormat::NPT_SEC: |
| { |
| stopTime = (int)(1000 * ((float)range.npt_end.npt_sec.sec + range.npt_end.npt_sec.milli_sec)); |
| } |
| break; |
| case NptTimeFormat::NPT_HHMMSS: |
| { |
| stopTime = 3600000 * range.npt_end.npt_hhmmss.hours + 60000 * range.npt_end.npt_hhmmss.min + 1000 * range.npt_end.npt_hhmmss.sec + (int)(100 * range.npt_end.npt_hhmmss.frac_sec); |
| } |
| break; |
| } |
| } |
| else |
| { |
| stopTime = false; |
| } |
| } |
| break; |
| case RtspRangeType::SMPTE_RANGE: |
| case RtspRangeType::SMPTE_25_RANGE: |
| case RtspRangeType::SMPTE_30_RANGE: |
| { |
| if (range.start_is_set) |
| { |
| startTime = 3600000 * range.smpte_start.hours + 60000 * range.smpte_start.minutes + 1000 * range.smpte_start.seconds; |
| } |
| else |
| { |
| startTime = 0; |
| } |
| if (range.end_is_set) |
| { |
| stopTime = 3600000 * range.smpte_end.hours + 60000 * range.smpte_end.minutes + 1000 * range.smpte_end.seconds; |
| } |
| else |
| { |
| stopTime = 0; |
| } |
| } |
| break; |
| case RtspRangeType::ABS_RANGE: |
| { |
| startTime = 0; |
| stopTime = 0; |
| } |
| break; |
| case RtspRangeType::UNKNOWN_RANGE: |
| case RtspRangeType::INVALID_RANGE: |
| { |
| startTime = 0; |
| stopTime = 0; |
| return -1; |
| } |
| // break; This statement was removed to avoid compiler warning for Unreachable Code |
| |
| default: |
| { |
| startTime = 0; |
| stopTime = 0; |
| return -1; |
| } |
| // break; This statement was removed to avoid compiler warning for Unreachable Code |
| } |
| return 0; |
| } |
| |
| OSCL_EXPORT_REF int SDP_Parser::getNumberOfTracks() |
| { |
| return mediaArrayIndex; |
| } |
| |
| OSCL_EXPORT_REF int SDP_Parser::setNumberOfTracks(int tracks) |
| { |
| return (mediaArrayIndex = tracks); |
| } |
| |
| |