1 /* ------------------------------------------------------------------ 2 * Copyright (C) 1998-2009 PacketVideo 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 * express or implied. 14 * See the License for the specific language governing permissions 15 * and limitations under the License. 16 * ------------------------------------------------------------------- 17 */ 18 #include "sdp_parser.h" 19 #include "sdp_mediaparser_registry.h" 20 #include "oscl_string_utils.h" 21 #include "oscl_string_containers.h" 22 #include "oscl_str_ptr_len.h" 23 #include "base_media_info_parser.h" 24 #include "aac_media_info_parser.h" 25 #include "amr_media_info_parser.h" 26 #include "h263_media_info_parser.h" 27 #include "m4v_media_info_parser.h" 28 #include "still_image_media_info_parser.h" 29 #include "pcma_media_info_parser.h" 30 #include "pcmu_media_info_parser.h" 31 #include "oscl_vector.h" 32 #include "oscl_dll.h" 33 34 OSCL_DLL_ENTRY_POINT_DEFAULT() 35 struct mime_payload_pair 36 { 37 OsclMemoryFragment mime; 38 Oscl_Vector<int, SDPParserAlloc> payload_no; 39 }; 40 41 OSCL_EXPORT_REF SDP_Parser::SDP_Parser(SDPMediaParserRegistry*& regTable, bool sipSdp): 42 iLogger(NULL), 43 _pSDPMediaParserRegistry(regTable), 44 mediaArrayIndex(0), 45 applicationFlag(false), 46 isSipSdp(sipSdp) 47 { 48 iLogger = PVLogger::GetLoggerObject("SDP_Parser"); 49 } 50 51 52 OSCL_EXPORT_REF SDP_Parser::~SDP_Parser() 53 { 54 } 55 56 bool SDP_Parser::parse_rtpmap(const char *start, const char *end, int& rtp_payload, 57 OsclMemoryFragment& encoding_name) 58 { 59 const int len_of_rtpmap = 9; 60 61 // grab the endpoints 62 const char *sptr = start + len_of_rtpmap; 63 const char *eptr; 64 65 // skip to the first whitespace character 66 eptr = skip_to_whitespace(sptr, end); 67 if (eptr < sptr) 68 { 69 return false; 70 } 71 uint32 rtpPayload; 72 if (PV_atoi(sptr, 'd', (eptr - sptr), rtpPayload) == false) 73 { 74 return false; 75 } 76 rtp_payload = (int)rtpPayload; 77 78 // now get the encoding name 79 sptr = skip_whitespace(eptr, end); 80 if (sptr >= end) 81 { 82 return false; 83 } 84 85 // now skip to end of the encoding name 86 for (eptr = sptr; eptr < end && 87 (*eptr != ' ' && *eptr != '\t' && *eptr != '/'); 88 ++eptr); 89 90 if (eptr >= end) 91 { 92 return false; 93 } 94 95 encoding_name.ptr = (void *) sptr; 96 encoding_name.len = eptr - sptr; 97 98 return true; 99 } 100 101 102 int SDP_Parser::validate_media_line(const char *start, const char *end, Oscl_Vector<int, SDPParserAlloc>& payload_type, uint32& portNumber) 103 { 104 int len; 105 const char *sptr, *eptr; 106 107 sptr = start + 2; // start after the "m=" 108 // skip to end of media type 109 eptr = skip_to_whitespace(sptr, end); 110 if (eptr >= end) 111 { 112 return 0; 113 } 114 115 116 len = eptr - sptr; 117 // make sure type is supported 118 if (!oscl_CIstrncmp(sptr, "audio", len) || !oscl_CIstrncmp(sptr, "video", len) || 119 !oscl_CIstrncmp(sptr, "application", len)) 120 { 121 // the type is supported 122 // make sure there is only one payload type in the format list 123 124 // skip to start of port number 125 sptr = skip_whitespace(eptr, end); 126 if (sptr >= end) 127 { 128 return 0; 129 } 130 131 // skip to end of port number 132 eptr = skip_to_whitespace(sptr, end); 133 if (eptr <= sptr) 134 { 135 return 0; 136 } 137 138 const char *tmp_end_ptr = sptr; 139 const char SDP_FWD_SLASH[] = "/"; 140 141 OSCL_HeapString<SDPParserAlloc> restOfLine(tmp_end_ptr, eptr - tmp_end_ptr); 142 const char *slash = oscl_strstr(restOfLine.get_cstr(), SDP_FWD_SLASH); 143 144 if (slash == NULL) 145 { 146 // Get the port number 147 if (PV_atoi(sptr, 'd', (eptr - sptr), portNumber) == false) 148 { 149 return 0; 150 } 151 } 152 else 153 { 154 // Get the port number 155 if (PV_atoi(restOfLine.get_cstr(), 'd', (slash - restOfLine.get_cstr()), portNumber) == false) 156 { 157 return 0; 158 } 159 } 160 161 // skip to start of transport 162 sptr = skip_whitespace(eptr, end); 163 if (sptr >= end) 164 { 165 return 0; 166 } 167 168 // skip to end of transport 169 eptr = skip_to_whitespace(sptr, end); 170 if (eptr <= sptr) 171 { 172 return 0; 173 } 174 175 // skip to start of format list 176 sptr = skip_whitespace(eptr, end); 177 if (sptr >= end) 178 { 179 return 0; 180 } 181 182 // skip to end of first payload arg 183 eptr = skip_to_whitespace(sptr, end); 184 if (eptr <= sptr) 185 { 186 return 0; 187 } 188 189 // record the payload type for non-application m= lines 190 if (oscl_strncmp(start + 2, "application", len)) 191 { 192 uint32 payloadType; 193 194 while (sptr < end) 195 { 196 if (PV_atoi(sptr, 'd', (eptr - sptr), payloadType) == false) 197 { 198 return 0; 199 } 200 201 payload_type.push_back(payloadType); 202 203 sptr = skip_to_whitespace(sptr, end); 204 sptr = skip_whitespace_and_line_term(eptr, end); 205 eptr = skip_whitespace_and_line_term(eptr, end); 206 eptr = skip_to_whitespace(eptr, end); 207 } 208 } 209 else 210 { 211 uint32 len = OSCL_MIN((uint32)(eptr - start), oscl_strlen("IMAGE")); 212 if (!oscl_strncmp(start, "IMAGE", len)) 213 { 214 applicationFlag = true; 215 } 216 else //don't support this media. so skip the section 217 return 0; 218 } 219 220 if (sptr < end) 221 { 222 return 0; 223 } 224 225 return 1; 226 } 227 228 return 0; 229 230 } 231 232 OSCL_EXPORT_REF 233 SDP_ERROR_CODE SDP_Parser::parseSDP(const char *sdpText, int text_length, SDPInfo *sdp) 234 { 235 int index = 0, sdpIndex = 0; 236 237 const char *end_ptr = sdpText + text_length ; // Point just beyond the end 238 const char *section_start_ptr; 239 const char *section_end_ptr; 240 const char *line_start_ptr, *line_end_ptr; 241 bool session_info_parsed = false; 242 243 /**************************************************************************/ 244 245 // The purpose of this outer loop is to partition the SDP into different 246 // sections to be passed off to session-level parsers or media-level parsers. 247 // We just need to find the boundaries and pass the appropriate sections 248 // of code to the subparsers. 249 250 sdpIndex = 0; 251 index = 0; 252 253 // these track whether media and session-level sections have already 254 // been found 255 int media_sections_found = 0; 256 int session_section_found = 0; 257 258 // skip any leading whitespace including line terminators 259 section_start_ptr = skip_whitespace_and_line_term(sdpText, end_ptr); 260 261 while ((section_start_ptr - sdpText) < text_length) 262 { 263 if (!get_next_line(section_start_ptr, end_ptr, 264 line_start_ptr, line_end_ptr)) 265 { 266 break; 267 } 268 269 // figure out the type of section 270 if (!oscl_strncmp(line_start_ptr, "v=", 2)) 271 { 272 // this is the session-level 273 if (media_sections_found || session_section_found) 274 { 275 // there were already media sections or already a session-level section 276 // so a session-level section at this point is not allowed. 277 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Duplicate Session Sections")); 278 return SDP_BAD_FORMAT; 279 } 280 281 section_end_ptr = line_end_ptr; 282 283 // record that the session-level section has been found 284 session_section_found = 1; 285 286 while (get_next_line(section_end_ptr, end_ptr, 287 line_start_ptr, line_end_ptr)) 288 { 289 // check if this is the start of another section 290 if (!oscl_strncmp(line_start_ptr, "v=", 2) || 291 !oscl_strncmp(line_start_ptr, "m=", 2)) 292 { 293 break; 294 } 295 section_end_ptr = line_end_ptr; 296 } 297 298 299 OsclMemoryFragment session_frag; 300 session_frag.ptr = (void *)section_start_ptr; 301 session_frag.len = section_end_ptr - section_start_ptr; 302 303 SDP_ERROR_CODE retval = 304 parseSDPSessionInfo(section_start_ptr, 305 section_end_ptr - section_start_ptr, 306 sdp); 307 if (retval != SDP_SUCCESS) 308 { 309 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - parseSDPSessionInfo Failed=%d", retval)); 310 return retval; 311 } 312 else 313 { 314 session_info_parsed = true; 315 } 316 } 317 else if (!oscl_strncmp(line_start_ptr, "m=", 2)) 318 { 319 320 // now look for the end of the section 321 section_end_ptr = line_end_ptr; 322 bool supported_media = true; 323 324 ++media_sections_found; 325 sdp->setSegmentCount(media_sections_found); 326 327 /* SUPPORTING MULTIPLE PAYLOAD TYPE PER MEDIA NOW */ 328 // check to see how many payload types are present 329 Oscl_Vector<int, SDPParserAlloc> payload_type; 330 Oscl_Vector<int, SDPParserAlloc> rtpmap_pt; 331 Oscl_Vector<OsclMemoryFragment, SDPParserAlloc> encoding_name_vector; 332 333 uint32 portNumber = 0; 334 if (!validate_media_line(line_start_ptr, line_end_ptr, payload_type, portNumber)) 335 { 336 // skip this section 337 supported_media = false; 338 } 339 else 340 { 341 PVMF_SDP_PARSER_LOGINFO((0, "SDP_Parser::parseSDP - Validated MediaSection")); 342 } 343 344 int rtpmap_lines = 0; 345 346 // get the next line 347 OsclMemoryFragment encoding_name; 348 encoding_name.ptr = NULL; 349 encoding_name.len = 0; 350 351 Oscl_Vector<int, SDPParserAlloc> AltId; 352 while (get_next_line(section_end_ptr, end_ptr, line_start_ptr, line_end_ptr)) 353 { 354 // check if this is the start of another section 355 if (!oscl_strncmp(line_start_ptr, "v=", 2) || 356 !oscl_strncmp(line_start_ptr, "m=", 2)) 357 { 358 break; 359 } 360 if (supported_media && (applicationFlag == false)) 361 { 362 // check for lines which will give the media type 363 // so the parser can be allocated. Simply look for 364 // the "a=rtpmap" lines which contain the MIME type. 365 StrPtrLen rtpmap_str("a=rtpmap:"); 366 if (!oscl_strncmp(line_start_ptr, rtpmap_str.c_str(), rtpmap_str.length())) 367 { 368 ++rtpmap_lines; 369 int rtpmap_cu; 370 // get encoding name 371 if (!parse_rtpmap(line_start_ptr, line_end_ptr, rtpmap_cu, encoding_name)) 372 { 373 // invalid format 374 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - parse_rtpmap Failed")); 375 return SDP_BAD_MEDIA_FORMAT; 376 } 377 rtpmap_pt.push_back(rtpmap_cu); 378 encoding_name_vector.push_back(encoding_name); 379 OSCL_StackString<15> mime((const char*)(encoding_name.ptr), encoding_name.len); 380 PVMF_SDP_PARSER_LOGINFO((0, "SDP_Parser::parseSDP - a=rtpmap mime=%s", mime.get_cstr())); 381 } 382 StrPtrLen alt_def("a=alt-default-id:"); 383 if (!oscl_strncmp(line_start_ptr, alt_def.c_str(), alt_def.length())) 384 { 385 uint32 id; 386 const char *sptr = line_start_ptr + alt_def.length(); 387 sptr = skip_whitespace(sptr, line_end_ptr); 388 if (!PV_atoi(sptr, 'd', line_end_ptr - sptr, id)) 389 { 390 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing a=alt-default-id: Failed")); 391 return SDP_BAD_MEDIA_ALT_ID; 392 } 393 AltId.push_back(id); 394 } 395 StrPtrLen alt_id("a=alt:"); 396 if (!oscl_strncmp(line_start_ptr, alt_id.c_str(), alt_id.length())) 397 { 398 uint32 id; 399 const char *sptr = line_start_ptr + alt_id.length(); 400 sptr = skip_whitespace(sptr, line_end_ptr); 401 const char *eptr = sptr; 402 for (; *eptr != ':'; eptr++); 403 if (!PV_atoi(sptr, 'd', eptr - sptr, id)) 404 { 405 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing a=alt: Failed")); 406 return SDP_BAD_MEDIA_ALT_ID; 407 } 408 if (AltId.back() != (int)id) 409 AltId.push_back(id); 410 } 411 412 // fmtp and framesize payload check is provided below 413 // this is done to make sure that the payload coming in these fields 414 // is one of the payloads in the m= segment 415 StrPtrLen fmtp("a=fmtp:"); 416 if (!oscl_strncmp(line_start_ptr, fmtp.c_str(), fmtp.length())) 417 { 418 uint32 payload; 419 const char *sptr = line_start_ptr + fmtp.length(); 420 sptr = skip_whitespace(sptr, line_end_ptr); 421 const char* eptr = skip_to_whitespace(sptr, line_end_ptr); 422 if (!PV_atoi(sptr, 'd', eptr - sptr, payload)) 423 { 424 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing a=fmtp: Failed")); 425 return SDP_BAD_MEDIA_FORMAT; 426 } 427 // The format is proper match the payload with payloads in m= segment 428 bool matched = false; 429 for (uint32 ii = 0; ii < payload_type.size(); ii++) 430 { 431 if (payload == (uint32)payload_type[ii]) 432 { 433 matched = true; 434 break; 435 } 436 } 437 if (!matched) 438 { 439 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Payload Mismatch in fmtp line")); 440 return SDP_PAYLOAD_MISMATCH; 441 } 442 } 443 StrPtrLen framesize("a=framesize:"); 444 if (!oscl_strncmp(line_start_ptr, framesize.c_str(), framesize.length())) 445 { 446 uint32 payload; 447 const char *sptr = line_start_ptr + framesize.length(); 448 sptr = skip_whitespace(sptr, line_end_ptr); 449 const char* eptr = skip_to_whitespace(sptr, line_end_ptr); 450 if (!PV_atoi(sptr, 'd', eptr - sptr, payload)) 451 { 452 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing a=framesize: Failed")); 453 return SDP_BAD_MEDIA_FORMAT; 454 } 455 // The format is proper match the payload with payloads in m= segment 456 bool matched = false; 457 for (uint32 ii = 0; ii < payload_type.size(); ii++) 458 { 459 if (payload == (uint32)payload_type[ii]) 460 { 461 matched = true; 462 break; 463 } 464 } 465 if (!matched) 466 { 467 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Payload Mismatch in a=framesize: line")); 468 return SDP_PAYLOAD_MISMATCH; 469 } 470 } 471 472 } // end if media is supported 473 else 474 { 475 PVMF_SDP_PARSER_LOGINFO((0, "SDP_Parser::parseSDP - Skipping over an entire m= section")); 476 } 477 478 section_end_ptr = line_end_ptr; 479 } // end loop over the entire media section 480 481 482 // The checking for rtpmap vs payloads is not required if the port number is 0 in case it is a sip sdp 483 bool check_for_rtpmap = true; 484 if (isSipSdp && portNumber == 0) 485 { 486 check_for_rtpmap = false; 487 } 488 489 // Checking for rtpmap with the payloads 490 if (supported_media && check_for_rtpmap) 491 { 492 // Validate the payload type and rtpmap if required 493 int static_payload_count = 0; 494 int ii = 0; 495 for (; ii < (int)payload_type.size(); ii++) 496 { 497 // If any payload_type is in static range we do not care 498 // for the rtpmap field. We will process for this static payload type sdp 499 // the dynamic payload type if any will be ignored if it's rtpmap 500 // is missing 501 if ((payload_type[ii] >= FIRST_STATIC_PAYLOAD) && 502 (payload_type[ii] <= LAST_STATIC_PAYLOAD)) 503 { 504 PVMF_SDP_PARSER_LOGINFO((0, "SDP_Parser::parseSDP - Static Payload =%d", payload_type[ii])); 505 static_payload_count++; 506 } 507 } 508 if (static_payload_count == 0) 509 { 510 // The payload type present are all in the dynamic range 511 if (rtpmap_pt.size() != payload_type.size()) 512 { 513 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Mismatch between number of payloads and rtpmap lines")); 514 return SDP_BAD_MEDIA_FORMAT; 515 } 516 for (int ii = 0; ii < (int)rtpmap_pt.size(); ii++) 517 { 518 if (rtpmap_pt[ii] != payload_type[ii]) 519 { 520 // this is an error 521 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Incorrect payload number in rtpmap line")); 522 return SDP_PAYLOAD_MISMATCH; 523 } 524 } 525 } 526 else if (static_payload_count >= 1) 527 { 528 // All of the payloads can either be static or one of them 529 // for every dynamic payload there should be matching rtpmap field 530 if (rtpmap_pt.size() != (payload_type.size() - static_payload_count)) 531 { 532 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Mismatch between number of payloads and rtpmap lines")); 533 return SDP_BAD_MEDIA_FORMAT; 534 } 535 for (uint32 rtpmap_count = 0; rtpmap_count < rtpmap_pt.size(); rtpmap_count++) 536 { 537 bool match_found = false; 538 for (int jj = 0; jj < (int)payload_type.size(); jj++) 539 { 540 if (rtpmap_pt[rtpmap_count] == payload_type[jj]) 541 { 542 match_found = true; 543 break; 544 } 545 } 546 if (match_found == false) 547 { 548 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - No matching rtpmap line")); 549 // this is an error 550 return SDP_PAYLOAD_MISMATCH; 551 } 552 } 553 } 554 } 555 556 if (session_info_parsed == false) 557 { 558 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Missing Session Section")); 559 return SDP_BAD_FORMAT; 560 } 561 562 if (supported_media) 563 { 564 StrPtrLen image("X-MP4V-IMAGE"); 565 if (applicationFlag == true) 566 { 567 if (rtpmap_lines == 0) 568 { 569 rtpmap_lines++; 570 encoding_name.ptr = (void *) image.c_str(); 571 encoding_name.len = image.length(); 572 applicationFlag = false; 573 encoding_name_vector.push_back(encoding_name); 574 } 575 } 576 577 // Compose all media encoding names and put them in one vector 578 // this will carry all encoding names including static and dynamic PT 579 StrPtrLen pcma(PVMF_MIME_PCMA); 580 StrPtrLen pcmu(PVMF_MIME_PCMU); 581 StrPtrLen amr("AMR"); 582 Oscl_Vector<OsclMemoryFragment, SDPParserAlloc> all_media_encoding_names; 583 uint32 ii = 0; 584 uint32 jj = 0; 585 for (; ii < payload_type.size(); ii++) 586 { 587 if (payload_type[ii] == PVMF_PCMU) 588 { 589 rtpmap_lines++; 590 encoding_name.ptr = (void *) pcmu.c_str(); 591 encoding_name.len = pcmu.length(); 592 } 593 else if (payload_type[ii] == PVMF_PCMA) 594 { 595 rtpmap_lines++; 596 encoding_name.ptr = (void *) pcma.c_str(); 597 encoding_name.len = pcma.length(); 598 } 599 else if (check_for_rtpmap == false) 600 { 601 // This means that the port is 0 and they payload is in dynamic range 602 // rtpmap field is not present. 603 // To map it internally let's put it under PCMU again 604 rtpmap_lines++; 605 encoding_name.ptr = (void *) pcmu.c_str(); 606 encoding_name.len = pcmu.length(); 607 } 608 else 609 { 610 // All other payload encoding names are already present in the 611 // encoding_name_vector. 612 if (jj < encoding_name_vector.size()) 613 { 614 encoding_name = encoding_name_vector[jj]; 615 jj++; 616 } 617 } 618 all_media_encoding_names.push_back(encoding_name); 619 } 620 621 // compose all the above information in the following format 622 // Any Mime type coming repeatedly with different payload numbers 623 // Then club them together 624 Oscl_Vector<mime_payload_pair, SDPParserAlloc> mime_payload_pair_vector; 625 626 for (uint32 ll = 0; ll < payload_type.size(); ll++) 627 { 628 if (check_for_rtpmap == true) 629 { 630 bool matched = false; 631 uint32 ii = 0; 632 for (; ii < mime_payload_pair_vector.size(); ii++) 633 { 634 if (oscl_strncmp((char*)mime_payload_pair_vector[ii].mime.ptr, 635 (char*)all_media_encoding_names[ll].ptr, 636 all_media_encoding_names[ll].len) == 0) 637 { 638 matched = true; 639 break; 640 } 641 } 642 if (matched) 643 { 644 mime_payload_pair_vector[ii].payload_no.push_back(payload_type[ll]); 645 } 646 else 647 { 648 mime_payload_pair mpp; 649 mpp.payload_no.push_back(payload_type[ll]); 650 mpp.mime.len = all_media_encoding_names[ll].len; 651 mpp.mime.ptr = all_media_encoding_names[ll].ptr; 652 mime_payload_pair_vector.push_back(mpp); 653 } 654 } 655 else 656 { 657 // It is a sip sdp with port = 0. Hence do not make specific checks 658 mime_payload_pair mpp; 659 mpp.payload_no.push_back(payload_type[ll]); 660 mpp.mime.len = all_media_encoding_names[ll].len; 661 mpp.mime.ptr = all_media_encoding_names[ll].ptr; 662 mime_payload_pair_vector.push_back(mpp); 663 } 664 665 } 666 667 if (rtpmap_lines >= 1) 668 { 669 SDPMediaParserFactory *mediaParserFactory; 670 SDPBaseMediaInfoParser *mediaParser; 671 SDP_ERROR_CODE retval; 672 673 for (uint32 kk = 0; kk < mime_payload_pair_vector.size(); kk++) 674 { 675 encoding_name = mime_payload_pair_vector[kk].mime; 676 if ((mediaParserFactory = 677 _pSDPMediaParserRegistry->lookupSDPMediaParserFactory(encoding_name)) != NULL) 678 { 679 mediaParser = mediaParserFactory->createSDPMediaParserInstance(); 680 if (mediaParser == NULL) 681 { 682 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Unable to create media parser")); 683 return SDP_FAILURE; 684 } 685 if (AltId.size() > 0) 686 { 687 int alt_id; 688 bool alt_def_id = false; 689 for (int ss = 0; ss < (int)AltId.size(); ss++) 690 { 691 if (ss == 0) alt_def_id = true; 692 else alt_def_id = false; 693 694 alt_id = AltId[ss]; 695 696 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) 697 { 698 OSCL_StackString<8> mime((const char*)(encoding_name.ptr), encoding_name.len); 699 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing m= section failed, mime=%s", mime.get_cstr())); 700 OSCL_DELETE((mediaParser)); 701 sdp->freeLastMediaInfoObject(); 702 return retval; 703 } 704 705 } 706 } 707 else 708 { 709 if ((retval = mediaParser->parseMediaInfo(section_start_ptr, section_end_ptr - section_start_ptr, sdp, mime_payload_pair_vector[kk].payload_no, isSipSdp)) != SDP_SUCCESS) 710 { 711 OSCL_StackString<8> mime((const char*)(encoding_name.ptr), encoding_name.len); 712 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing m= section failed, mime=%s", mime.get_cstr())); 713 OSCL_DELETE((mediaParser)); 714 sdp->freeLastMediaInfoObject(); 715 return retval; 716 } 717 } 718 sdp->IncrementAlternateMediaInfoVectorIndex(); 719 OSCL_DELETE((mediaParser)); 720 } 721 mediaParser = NULL; 722 } // End of for 723 } 724 if (rtpmap_lines == 0) // no rtpmap found in media 725 { 726 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing m= section failed, No rtpmap line")); 727 return SDP_BAD_MEDIA_MISSING_RTPMAP; 728 } 729 } 730 } // end this is a media section 731 else 732 { 733 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Unrecognized Syntax")); 734 // unknown section type -- this is an error 735 return SDP_FAILURE; 736 } 737 738 section_start_ptr = skip_whitespace_and_line_term(section_end_ptr, end_ptr); 739 740 } 741 { 742 //for SDP which doesn't have session level range, set the session level range 743 //to be the MAX of media ranges. 744 if (NULL == sdp->getSessionInfo()) 745 { 746 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Missing Session Info")); 747 return SDP_BAD_FORMAT; 748 } 749 RtspRangeType *mySdpRange = ((RtspRangeType *)sdp->getSessionInfo()->getRange()); 750 if (NULL == mySdpRange) 751 { 752 PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Unable to retrieve session range")); 753 return SDP_BAD_FORMAT; 754 } 755 if (mySdpRange->format == RtspRangeType::INVALID_RANGE) 756 { 757 PVMF_SDP_PARSER_LOGINFO((0, "SDP_Parser::parseSDP - No Valid Session Range - Setting it to Max of all media ranges")); 758 for (int32 i = sdp->getNumMediaObjects() - 1; i >= 0; i--) 759 { 760 Oscl_Vector<mediaInfo*, SDPParserAlloc> mediaInfoVec = 761 sdp->getMediaInfo(i); 762 for (uint32 j = 0; j < mediaInfoVec.size(); j++) 763 { 764 mediaInfo* mInfo = mediaInfoVec[j]; 765 if (mInfo == NULL) 766 { 767 continue; 768 } 769 const RtspRangeType *mInfoSdpRange = mInfo->getRtspRange(); 770 if (NULL == mInfoSdpRange) 771 { 772 continue; 773 } 774 if (mInfoSdpRange->format != RtspRangeType::NPT_RANGE) 775 { 776 continue; 777 } 778 if (mySdpRange->format == RtspRangeType::INVALID_RANGE) 779 { 780 *mySdpRange = *mInfoSdpRange; 781 } 782 if (!mInfoSdpRange->end_is_set) 783 {//live streaming 784 *mySdpRange = *mInfoSdpRange; 785 mySdpRange->start_is_set = true;//just to make sure 786 mySdpRange->npt_start.npt_format = NptTimeFormat::NOW; 787 return SDP_SUCCESS; 788 } 789 if (mInfoSdpRange->npt_start.npt_format == NptTimeFormat::NPT_SEC) 790 { 791 if (mInfoSdpRange->npt_start.npt_sec.sec < mySdpRange->npt_start.npt_sec.sec) 792 { 793 mySdpRange->npt_start.npt_sec = mInfoSdpRange->npt_start.npt_sec; 794 } 795 else if ((mInfoSdpRange->npt_start.npt_sec.sec == mySdpRange->npt_start.npt_sec.sec) 796 && ((mInfoSdpRange->npt_start.npt_sec.milli_sec < mySdpRange->npt_start.npt_sec.milli_sec))) 797 { 798 mySdpRange->npt_start.npt_sec = mInfoSdpRange->npt_start.npt_sec; 799 } 800 } 801 if (mInfoSdpRange->npt_end.npt_format == NptTimeFormat::NPT_SEC) 802 { 803 if (mInfoSdpRange->npt_end.npt_sec.sec > mySdpRange->npt_end.npt_sec.sec) 804 { 805 mySdpRange->npt_end.npt_sec = mInfoSdpRange->npt_end.npt_sec; 806 } 807 else if ((mInfoSdpRange->npt_end.npt_sec.sec == mySdpRange->npt_end.npt_sec.sec) 808 && ((mInfoSdpRange->npt_end.npt_sec.milli_sec > mySdpRange->npt_end.npt_sec.milli_sec))) 809 { 810 mySdpRange->npt_end.npt_sec = mInfoSdpRange->npt_end.npt_sec; 811 } 812 } 813 } 814 } 815 } 816 } 817 return SDP_SUCCESS; 818 } 819 820 OSCL_EXPORT_REF SDP_ERROR_CODE 821 SDP_Parser::parseSDPDownload(const char *sdpText, 822 int length, 823 SDPInfo *sdp, 824 movieInfo *mv) 825 { 826 SDP_ERROR_CODE retval = parseSDP(sdpText, length, sdp); 827 if (retval != SDP_SUCCESS) 828 { 829 mv->trackCount = 0; 830 mv->movieName[0] = '\0'; 831 mv->creationDate[0] = '\0'; 832 return retval; 833 } 834 else 835 { 836 /*Get Movie name*/ 837 int len = oscl_strlen(sdp->getSessionInfo()->getSessionName()); 838 if (len >= MAX_STRING_LEN) 839 { 840 oscl_strncpy(mv->movieName, sdp->getSessionInfo()->getSessionName(), (MAX_STRING_LEN - 1)); 841 mv->movieName[MAX_STRING_LEN-1] = '\0'; 842 } 843 else 844 { 845 oscl_strncpy(mv->movieName, sdp->getSessionInfo()->getSessionName(), len); 846 mv->movieName[len] = '\0'; 847 } 848 849 /*Get creation date*/ 850 len = oscl_strlen(sdp->getSessionInfo()->getCreationDate()); 851 if (len >= MAX_STRING_LEN) 852 { 853 oscl_strncpy(mv->creationDate, sdp->getSessionInfo()->getCreationDate(), (MAX_STRING_LEN - 1)); 854 mv->creationDate[MAX_STRING_LEN-1] = '\0'; 855 } 856 else 857 { 858 oscl_strncpy(mv->creationDate, sdp->getSessionInfo()->getCreationDate(), len); 859 mv->creationDate[len] = '\0'; 860 } 861 862 /*Get number of tracks*/ 863 mv->trackCount = sdp->getNumMediaObjects(); 864 865 /*Get start stop times*/ 866 convertToMilliSec(*sdp->getSessionInfo()->getRange(), mv->duration.startTime, mv->duration.stopTime); 867 868 /*Get MIMEType and other track info*/ 869 for (int ii = 0; ii < mv->trackCount; ii++) 870 { 871 Oscl_Vector<mediaInfo*, SDPParserAlloc> mediaInfoVec = 872 sdp->getMediaInfo(ii); 873 874 /* 875 * There would only be one element in this vector 876 * for fast track download content. 877 */ 878 mediaInfo* minfo = mediaInfoVec[0]; 879 880 mv->TrackArray[ii].bitrate = minfo->getBitrate(); 881 len = oscl_strlen(minfo->getMIMEType()); 882 if (len >= MAX_STRING_LEN) 883 { 884 oscl_strncpy(mv->TrackArray[ii].codec_type, 885 minfo->getMIMEType(), 886 (MAX_STRING_LEN - 1)); 887 mv->TrackArray[ii].codec_type[MAX_STRING_LEN-1] = '\0'; 888 } 889 else 890 { 891 oscl_strncpy(mv->TrackArray[ii].codec_type, 892 minfo->getMIMEType(), 893 len); 894 mv->TrackArray[ii].codec_type[len] = '\0'; 895 } 896 const char *trackID = minfo->getControlURL(); 897 int track = 0; 898 if (trackID != NULL) 899 { 900 const char *locateID = oscl_strstr(trackID, "="); 901 if (locateID != NULL) 902 { 903 locateID += 1; 904 uint32 atoi_tmp; 905 PV_atoi(locateID, 'd', atoi_tmp); 906 track = atoi_tmp; 907 } 908 } 909 mv->TrackArray[ii].trackID = track; 910 } 911 } 912 return SDP_SUCCESS; 913 } 914 915 916 int 917 SDP_Parser::convertToMilliSec(RtspRangeType range , int &startTime, int &stopTime) 918 { 919 switch (range.format) 920 { 921 case RtspRangeType::NPT_RANGE: 922 { 923 if (range.start_is_set) 924 { 925 switch (range.npt_start.npt_format) 926 { 927 case NptTimeFormat::NOW: 928 { 929 startTime = 0; 930 } 931 break; 932 case NptTimeFormat::NPT_SEC: 933 { 934 startTime = (int)(1000 * ((float)range.npt_start.npt_sec.sec + range.npt_start.npt_sec.milli_sec)); 935 } 936 break; 937 case NptTimeFormat::NPT_HHMMSS: 938 { 939 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); 940 } 941 break; 942 } 943 } 944 else 945 { 946 startTime = 0; 947 } 948 if (range.end_is_set) 949 { 950 switch (range.npt_end.npt_format) 951 { 952 case NptTimeFormat::NOW: 953 { 954 stopTime = 0; 955 } 956 break; 957 case NptTimeFormat::NPT_SEC: 958 { 959 stopTime = (int)(1000 * ((float)range.npt_end.npt_sec.sec + range.npt_end.npt_sec.milli_sec)); 960 } 961 break; 962 case NptTimeFormat::NPT_HHMMSS: 963 { 964 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); 965 } 966 break; 967 } 968 } 969 else 970 { 971 stopTime = false; 972 } 973 } 974 break; 975 case RtspRangeType::SMPTE_RANGE: 976 case RtspRangeType::SMPTE_25_RANGE: 977 case RtspRangeType::SMPTE_30_RANGE: 978 { 979 if (range.start_is_set) 980 { 981 startTime = 3600000 * range.smpte_start.hours + 60000 * range.smpte_start.minutes + 1000 * range.smpte_start.seconds; 982 } 983 else 984 { 985 startTime = 0; 986 } 987 if (range.end_is_set) 988 { 989 stopTime = 3600000 * range.smpte_end.hours + 60000 * range.smpte_end.minutes + 1000 * range.smpte_end.seconds; 990 } 991 else 992 { 993 stopTime = 0; 994 } 995 } 996 break; 997 case RtspRangeType::ABS_RANGE: 998 { 999 startTime = 0; 1000 stopTime = 0; 1001 } 1002 break; 1003 case RtspRangeType::UNKNOWN_RANGE: 1004 case RtspRangeType::INVALID_RANGE: 1005 { 1006 startTime = 0; 1007 stopTime = 0; 1008 return -1; 1009 } 1010 // break; This statement was removed to avoid compiler warning for Unreachable Code 1011 1012 default: 1013 { 1014 startTime = 0; 1015 stopTime = 0; 1016 return -1; 1017 } 1018 // break; This statement was removed to avoid compiler warning for Unreachable Code 1019 } 1020 return 0; 1021 } 1022 1023 OSCL_EXPORT_REF int SDP_Parser::getNumberOfTracks() 1024 { 1025 return mediaArrayIndex; 1026 } 1027 1028 OSCL_EXPORT_REF int SDP_Parser::setNumberOfTracks(int tracks) 1029 { 1030 return (mediaArrayIndex = tracks); 1031 } 1032 1033 1034