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
SDP_Parser(SDPMediaParserRegistry * & regTable,bool sipSdp)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
~SDP_Parser()52 OSCL_EXPORT_REF SDP_Parser::~SDP_Parser()
53 {
54 }
55
parse_rtpmap(const char * start,const char * end,int & rtp_payload,OsclMemoryFragment & encoding_name)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
validate_media_line(const char * start,const char * end,Oscl_Vector<int,SDPParserAlloc> & payload_type,uint32 & portNumber)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
parseSDP(const char * sdpText,int text_length,SDPInfo * sdp)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
parseSDPDownload(const char * sdpText,int length,SDPInfo * sdp,movieInfo * mv)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
convertToMilliSec(RtspRangeType range,int & startTime,int & stopTime)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
getNumberOfTracks()1023 OSCL_EXPORT_REF int SDP_Parser::getNumberOfTracks()
1024 {
1025 return mediaArrayIndex;
1026 }
1027
setNumberOfTracks(int tracks)1028 OSCL_EXPORT_REF int SDP_Parser::setNumberOfTracks(int tracks)
1029 {
1030 return (mediaArrayIndex = tracks);
1031 }
1032
1033
1034