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 "m4v_media_info_parser.h"
19 #include "oscl_string_utils.h"
20 #include "oscl_string_containers.h"
21
22 SDP_ERROR_CODE
parseMediaInfo(const char * buff,const int index,SDPInfo * sdp,payloadVector payload_vec,bool isSipSdp,int alt_id,bool alt_def_id)23 SDPMPEG4MediaInfoParser::parseMediaInfo(const char *buff, const int index, SDPInfo *sdp, payloadVector payload_vec, bool isSipSdp, int alt_id, bool alt_def_id)
24 {
25
26 const char *current_start = buff; //Pointer to the beginning of the media text
27 const char *end = buff + index; //Pointer to the end of the media text
28 const char *line_start_ptr, *line_end_ptr;
29 int VOLLength = 0;
30 int fmtp_cnt = 0 ;
31 bool framesize_found_in_fmtp = false;
32 SDPAllocDestructDealloc<uint8> SDP_alloc;
33
34
35 while (get_next_line(current_start, end,
36 line_start_ptr, line_end_ptr))
37 {
38 if ((!oscl_strncmp(line_start_ptr, "a=alt:", oscl_strlen("a=alt:"))) && (alt_def_id == false))
39 {
40 line_start_ptr += oscl_strlen("a=alt:");
41 for (; *line_start_ptr != ':'; line_start_ptr++);
42 line_start_ptr = line_start_ptr + 1;
43 }
44 if (!oscl_strncmp(line_start_ptr, "a=fmtp:", oscl_strlen("a=fmtp:")))
45 {
46 char *tmp_start_line, *tmp_end_line;
47 fmtp_cnt++ ;
48
49 tmp_start_line = (char *)line_start_ptr + oscl_strlen("a=fmtp:");
50 tmp_start_line = (char *)skip_whitespace(tmp_start_line, line_end_ptr);
51 if (tmp_start_line >= line_end_ptr)
52 {
53 break;
54 }
55 tmp_end_line = (char *)skip_to_whitespace(tmp_start_line, line_end_ptr);
56 if (tmp_end_line < tmp_start_line)
57 {
58 break;
59 }
60 tmp_start_line = tmp_end_line + 1;
61 tmp_start_line = (char *)skip_whitespace(tmp_start_line, line_end_ptr);
62 if (tmp_start_line >= line_end_ptr)
63 {
64 break;
65 }
66 int ii = 0;
67 const char *temp = tmp_start_line;
68 for (ii = 0; ii < (line_end_ptr - tmp_start_line) ; ii++)
69 {
70 if ((tmp_start_line[ii] == ';') || (ii == (line_end_ptr - tmp_start_line - 1)))
71 {
72 tmp_end_line = tmp_start_line + ii;
73 if ((line_end_ptr - tmp_start_line - 1) == ii)
74 {
75 tmp_end_line++;
76 }
77 if (!oscl_strncmp(temp, "config=", oscl_strlen("config=")))
78 {
79 int currentVOLLength;
80 temp += oscl_strlen("config=");
81 temp = skip_whitespace(temp, line_end_ptr);
82 if (temp >= line_end_ptr)
83 {
84 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - Bad config field"));
85 return SDP_BAD_MEDIA_FMTP;
86 }
87
88 currentVOLLength = (int)(tmp_end_line - temp) / 2;
89 if (VOLLength < currentVOLLength)
90 VOLLength = currentVOLLength;
91 }
92 if (tmp_end_line != line_end_ptr) temp = tmp_end_line + 1;
93 temp = skip_whitespace(temp, line_end_ptr);
94 if (temp >= line_end_ptr)
95 {
96 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format"));
97 return SDP_BAD_MEDIA_FMTP;
98 }
99
100 }
101 }
102 }
103
104
105 current_start = line_end_ptr + 1;
106 }
107
108 if (fmtp_cnt == 0 && isSipSdp == false)
109 {
110 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - No fmtp line found"));
111 return SDP_BAD_MEDIA_FORMAT;
112 }
113
114 if (VOLLength < 0)
115 {
116 VOLLength = 0;
117 }
118
119 bool altMedia = false;
120 if (!alt_id || (alt_def_id == true))
121 altMedia = false;
122 else
123 altMedia = true;
124
125 void *memory = sdp->alloc(sizeof(m4v_mediaInfo), altMedia);
126 if (NULL == memory)
127 {
128 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - memory allocation failure"));
129 return SDP_NO_MEMORY;
130 }
131 else
132 {
133 m4v_mediaInfo *m4Video = OSCL_PLACEMENT_NEW(memory, m4v_mediaInfo());
134
135 m4Video->setMediaInfoID(sdp->getMediaObjectIndex());
136
137 // Allocate memory to the payload specific objects
138 for (uint32 ii = 0; ii < payload_vec.size(); ii++)
139 {
140 void* mem = m4Video->alloc(sizeof(M4vPayloadSpecificInfoType));
141 if (mem == NULL)
142 {
143 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Memory allocation failure"));
144 return SDP_NO_MEMORY;
145 }
146 else
147 {
148 M4vPayloadSpecificInfoType* payload = OSCL_PLACEMENT_NEW(mem, M4vPayloadSpecificInfoType(payload_vec[ii]));
149 (void) payload;
150 }
151 }
152
153
154 if (alt_id && !alt_def_id)
155 {
156 sdp->copyFmDefMedia(m4Video);
157 //empty alternate & default track ID vectors.
158 m4Video->resetAlternateTrackId();
159 m4Video->resetDependentTrackId();
160 }
161
162 SDP_ERROR_CODE status = baseMediaInfoParser(buff, m4Video, index, alt_id, alt_def_id, isSipSdp);
163 if (status != SDP_SUCCESS)
164 {
165 return status;
166 }
167
168 current_start = buff;
169
170
171 while (get_next_line(current_start, end,
172 line_start_ptr, line_end_ptr))
173 {
174 switch (*line_start_ptr)
175 {
176 case 'a':
177 {
178 const char *sptr;
179 if ((!oscl_strncmp(line_start_ptr, "a=alt:", oscl_strlen("a=alt:"))) && (alt_def_id == false))
180 {
181 line_start_ptr += oscl_strlen("a=alt:");
182 for (; *line_start_ptr != ':'; line_start_ptr++);
183 line_start_ptr = line_start_ptr + 1;
184 }
185 if (!oscl_strncmp(line_start_ptr, "a=framerate:", oscl_strlen("a=framerate:")))
186 {
187 sptr = line_start_ptr + oscl_strlen("a=framerate:");
188 sptr = skip_whitespace(sptr, line_end_ptr);
189 if (sptr >= line_end_ptr)
190 {
191 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=framerate line format"));
192 return SDP_BAD_MEDIA_FRAME_RATE;
193 }
194 OsclFloat rate;
195 if (!PV_atof(sptr, line_end_ptr - sptr, rate))
196 return SDP_BAD_MEDIA_FORMAT;
197 ((m4v_mediaInfo *)m4Video)->setFrameRate(rate);
198 }
199 if (!oscl_strncmp(line_start_ptr, "a=I_frame_interval:", oscl_strlen("a=I_frame_interval:")))
200 {
201 sptr = line_start_ptr + oscl_strlen("a=I_frame_interval:");
202 sptr = skip_whitespace(sptr, line_end_ptr);
203 if (sptr >= line_end_ptr)
204 {
205 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=I_frame_interval line format"));
206 return SDP_BAD_MEDIA_FRAME_INTERVAL;
207 }
208 uint32 ifi;
209 if (PV_atoi(sptr, 'd', (line_end_ptr - sptr), ifi) == true)((m4v_mediaInfo *)m4Video)->setIFrameInterval(ifi);
210 }
211 if (!oscl_strncmp(line_start_ptr, "a=fmtp:", oscl_strlen("a=fmtp:")))
212 {
213 const char *tmp_start_line, *tmp_end_line;
214 tmp_start_line = line_start_ptr + oscl_strlen("a=fmtp:");
215 tmp_start_line = skip_whitespace(tmp_start_line, line_end_ptr);
216 if (tmp_start_line >= line_end_ptr)
217 {
218 break;
219 }
220 tmp_end_line = skip_to_whitespace(tmp_start_line, line_end_ptr);
221 if (tmp_end_line < tmp_start_line)
222 {
223 break;
224 }
225 uint32 payloadNumber;
226 if (PV_atoi(tmp_start_line, 'd', (tmp_end_line - tmp_start_line), payloadNumber) == false)
227 {
228 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - Bad payload number"));
229 return SDP_BAD_MEDIA_FMTP;
230 }
231 else
232 {
233 int p;
234 if (!m4Video->lookupPayloadNumber(payloadNumber, p))
235 {
236 fmtp_cnt--;
237 break;
238 }
239 }
240
241 M4vPayloadSpecificInfoType* payloadPtr =
242 (M4vPayloadSpecificInfoType*)m4Video->getPayloadSpecificInfoTypePtr(payloadNumber);
243 if (payloadPtr == NULL)
244 {
245 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - payload pointer not found for payload"));
246 return SDP_PAYLOAD_MISMATCH;
247 }
248
249 PVMF_SDP_PARSER_LOGINFO((0, "SDPM4VMediaInfoParser::parseMediaInfo - processing payload number : %d", payloadNumber));
250
251 tmp_start_line = tmp_end_line + 1;
252 tmp_start_line = skip_whitespace(tmp_start_line, line_end_ptr);
253 if (tmp_start_line >= line_end_ptr)
254 {
255 break;
256 }
257 int ii = 0;
258 const char *temp = tmp_start_line;
259 for (ii = 0; ii < (line_end_ptr - tmp_start_line) ; ii++)
260 {
261 if ((tmp_start_line[ii] == ';') || (ii == (line_end_ptr - tmp_start_line - 1)))
262 {
263 tmp_end_line = tmp_start_line + ii;
264 if (ii == (line_end_ptr - tmp_start_line - 1))
265 {
266 tmp_end_line += 1;
267 }
268 if (!oscl_strncmp(temp, "config=", oscl_strlen("config=")))
269 {
270 uint8 *mptr = SDP_alloc.allocate(VOLLength);
271 OsclRefCounterSA< SDPAllocDestructDealloc<uint8> > *refcnt = new OsclRefCounterSA< SDPAllocDestructDealloc<uint8> >(mptr);
272 OsclSharedPtr<uint8> VOLPtr(mptr, refcnt);
273
274 temp += oscl_strlen("config=");
275 temp = skip_whitespace(temp, line_end_ptr);
276 if (temp >= line_end_ptr)
277 {
278 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - Bad config field"));
279 return SDP_BAD_MEDIA_FMTP;
280 }
281 VOLLength = (int)(tmp_end_line - temp) / 2;
282 int idx = 0;
283 for (idx = 0; idx < VOLLength; idx++)
284 {
285 uint32 val;
286 //Set this value in the vol header array
287 if (PV_atoi((temp + 2*idx), 'x', 2 , val) == false)
288 {
289 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - Bad config field"));
290 return SDP_BAD_MEDIA_FMTP;
291 }
292
293 *(VOLPtr + idx) = (uint8)val;
294
295 }
296
297 payloadPtr->setVOLHeader(VOLPtr);
298 payloadPtr->setVOLHeaderSize(VOLLength);
299 payloadPtr->setDecoderSpecificInfo(VOLPtr);
300 payloadPtr->setDecoderSpecificInfoSize(VOLLength);
301
302 }
303 if (!oscl_strncmp(temp, "profile-level-id=", oscl_strlen("profile-level-id=")))
304 {
305 temp += oscl_strlen("profile-level-id=");
306 temp = skip_whitespace(temp, line_end_ptr);
307 if (temp > line_end_ptr)
308 {
309 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - Bad profile-level-id field"));
310 return SDP_BAD_MEDIA_FMTP;
311 }
312 uint32 pl;
313 if (PV_atoi(temp, 'd', tmp_end_line - temp , pl) == true)
314 payloadPtr->setProfileLevelID(pl);
315
316 }
317 if (!oscl_strncmp(temp, "framesize=", oscl_strlen("framesize=")))
318 {
319 temp += oscl_strlen("framesize=");
320 temp = skip_whitespace(temp, tmp_end_line);
321 framesize_found_in_fmtp = true;
322 if (temp > tmp_end_line)
323 {
324 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - Bad framesize field"));
325 return SDP_BAD_MEDIA_FMTP;
326 }
327 const char *end = NULL;
328 int idx = 0;
329 for (idx = 0; idx < (tmp_end_line - temp); idx++)
330 {
331 if (temp[idx] == '-')
332 {
333 end = temp + idx;
334 }
335 }
336 if (end == NULL)
337 {
338 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - framesize width info missing"));
339 return SDP_MISSING_MEDIA_DESCRIPTION;
340 }
341 uint32 width;
342 if (PV_atoi(temp, 'd', (end - temp), width) == true)
343 payloadPtr->setFrameWidth(width);
344 temp = end + 1;
345 temp = skip_whitespace(temp, tmp_end_line);
346 if (temp > tmp_end_line)
347 {
348 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - framesize height info missing"));
349 return SDP_BAD_MEDIA_FMTP;
350 }
351 uint32 height;
352 if (PV_atoi(temp, 'd', tmp_end_line - temp, height) == true)
353 payloadPtr->setFrameHeight(height);
354 }
355 if (!oscl_strncmp(temp, "decode_buf=", oscl_strlen("decode_buf=")))
356 {
357 temp += oscl_strlen("decode_buf=");
358 temp = skip_whitespace(temp, tmp_end_line);
359 if (temp > tmp_end_line)
360 {
361 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format - Bad decode_buf field"));
362 return SDP_BAD_MEDIA_FMTP;
363 }
364 uint32 dec;
365 if (PV_atoi(temp, 'd', tmp_end_line - temp, dec) == true)
366 payloadPtr->setMaxBufferSize(dec);
367 }
368 if (tmp_end_line != line_end_ptr) temp = tmp_end_line + 1;
369 temp = skip_whitespace(temp, line_end_ptr);
370 if (temp >= line_end_ptr)
371 {
372 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=fmtp line format"));
373 return SDP_BAD_MEDIA_FMTP;
374 }
375 }
376 }
377 }
378 StrPtrLen fmsize("a=framesize:");
379 if (!oscl_strncmp(line_start_ptr, fmsize.c_str(), fmsize.length()))
380 {
381 uint32 width, height;
382 const char *sptr = line_start_ptr + fmsize.length();
383 const char *eptr = skip_to_whitespace(sptr, line_end_ptr);
384
385
386 if (sptr > eptr)
387 {
388 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=framesize line format"));
389 return SDP_BAD_MEDIA_FRAMESIZE;
390 }
391 uint32 payloadNo;
392 if (PV_atoi(sptr, 'd', (eptr - sptr), payloadNo))
393 {
394 int p;
395 if (!((m4v_mediaInfo *)m4Video)->lookupPayloadNumber(payloadNo, p))
396 break;
397
398 }
399 else
400 {
401 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=framesize line format - Bad payload number"));
402 return SDP_BAD_MEDIA_FRAMESIZE;
403 }
404
405 M4vPayloadSpecificInfoType* payloadPtr2 =
406 (M4vPayloadSpecificInfoType*)m4Video->getPayloadSpecificInfoTypePtr(payloadNo);
407 if (payloadPtr2 == NULL)
408 {
409 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=framesize line format - payload pointer not found for payload"));
410 return SDP_PAYLOAD_MISMATCH;
411 }
412
413 sptr = eptr;
414 sptr = skip_whitespace(sptr , line_end_ptr);
415
416 for (; *eptr != '-' ; ++eptr);
417
418 if (!PV_atoi(sptr, 'd', eptr - sptr, width))
419 {
420 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - Bad a=framesize line format"));
421 return SDP_BAD_MEDIA_FRAMESIZE;
422 }
423
424 eptr = eptr + 1;
425 sptr = eptr;
426 if (sptr > line_end_ptr)
427 return SDP_BAD_MEDIA_FRAMESIZE;
428 eptr = skip_to_line_term(sptr, line_end_ptr);
429 if (!PV_atoi(sptr, 'd', eptr - sptr, height))
430 return SDP_BAD_MEDIA_FRAMESIZE;
431
432 if (framesize_found_in_fmtp)
433 {
434 if ((int)width != payloadPtr2->getFrameWidth() || (int)height != payloadPtr2->getFrameHeight())
435 {
436 return SDP_BAD_MEDIA_FRAMESIZE;
437 }
438
439 }
440 else
441 {
442 payloadPtr2->setFrameWidth(width);
443 payloadPtr2->setFrameHeight(height);
444 }
445
446 }
447 }
448 break;
449 default:
450 break;
451 }
452 current_start = line_end_ptr;
453 }
454
455 sessionDescription *session = sdp->getSessionInfo();
456
457 const char *altGroupBW = session->getAltGroupBW();
458 int length = session->getAltGroupBWLength();
459
460 if (length > 0)
461 {
462 status = setDependentMediaId(altGroupBW, length, m4Video, alt_id);
463 if (status != SDP_SUCCESS)
464 return SDP_BAD_MEDIA_ALT_ID;
465 }
466
467 const char *altGroupLANG = session->getAltGroupLANG();
468 length = session->getAltGroupLANGLength();
469
470 if (length > 0)
471 {
472 status = setDependentMediaId(altGroupLANG, length, m4Video, alt_id);
473 if (status != SDP_SUCCESS)
474 return SDP_BAD_MEDIA_ALT_ID;
475 }
476
477 if (m4Video->getCFieldStatus() || session->getCFieldStatus())
478 {
479 //if sample rate is zero override with defaults
480 Oscl_Vector<PayloadSpecificInfoTypeBase*, SDPParserAlloc> payloadSpecificInfoVector =
481 m4Video->getPayloadSpecificInfoVector();
482 for (int ii = 0; ii < (int)payloadSpecificInfoVector.size(); ii++)
483 {
484 if (payloadSpecificInfoVector[ii]->getSampleRate() == 0)
485 {
486 payloadSpecificInfoVector[ii]->sampleRate =
487 PVMF_SDP_DEFAULT_MPEG4_VIDEO_SAMPLE_RATE;
488 }
489 }
490 return SDP_SUCCESS;
491 }
492 else
493 {
494 PVMF_SDP_PARSER_LOGERROR((0, "SDPM4VMediaInfoParser::parseMediaInfo - No C field present"));
495 return SDP_FAILURE_NO_C_FIELD;
496 }
497 }
498
499 }
500
501