Bug 1285646 - Clean up the repetitive code in sdp_parse_attr_fmtp. r=drno
authorMichael Froman <mfroman@mozilla.com>
Wed, 13 Jul 2016 18:25:22 -0500
changeset 319908 bd422e06289a9d753b9f3f26334cb0fd404366ad
parent 319907 5074747b77f0e344aa5131b817e1e6873d73a398
child 319909 93fc611f02350d598b5131a64a0b8e10a64113bd
push id20749
push userryanvm@gmail.com
push dateSat, 29 Oct 2016 13:21:21 +0000
treeherderfx-team@1b170b39ed6b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdrno
bugs1285646
milestone52.0a1
Bug 1285646 - Clean up the repetitive code in sdp_parse_attr_fmtp. r=drno MozReview-Commit-ID: 9umKSyVh0Ha
media/webrtc/signaling/src/sdp/sipcc/sdp_attr.c
media/webrtc/signaling/src/sdp/sipcc/sdp_attr_access.c
media/webrtc/signaling/test/sdp_unittests.cpp
--- a/media/webrtc/signaling/src/sdp/sipcc/sdp_attr.c
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_attr.c
@@ -531,16 +531,73 @@ static sdp_result_e sdp_verify_attr_fmtp
  *        single number or a range separated by a '-'.
  *        Example:  fmtp:101 1,3-15,20
  * Video codecs have annexes that can be listed in the following legal formats:
  * a) a=fmtp:34 param1=token;D;I;J;K=1;N=2;P=1,3
  * b) a=fmtp:34 param1=token;D;I;J;K=1;N=2;P=1,3;T
  * c) a=fmtp:34 param1=token;D;I;J
  *
  */
+sdp_result_e sdp_get_fmtp_tok(sdp_t *sdp_p,
+                              const char** fmtp_ptr,
+                              const char* fmtp_name,
+                              char* buf,
+                              size_t buf_size,
+                              char** tok)
+{
+    sdp_result_e result1 = SDP_SUCCESS;
+
+    *fmtp_ptr = sdp_getnextstrtok(*fmtp_ptr, buf, buf_size, "; \t", &result1);
+    if (result1 != SDP_SUCCESS) {
+        *fmtp_ptr = sdp_getnextstrtok(*fmtp_ptr, buf, buf_size, " \t", &result1);
+        if (result1 != SDP_SUCCESS) {
+            sdp_attr_fmtp_no_value(sdp_p, fmtp_name);
+            return SDP_INVALID_PARAMETER;
+        }
+    }
+    *tok = buf;
+    (*tok)++;
+
+    return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_get_fmtp_tok_val(sdp_t *sdp_p,
+                              const char** fmtp_ptr,
+                              const char* fmtp_name,
+                              char* buf,
+                              size_t buf_size,
+                              char** tok,
+                              unsigned long* strtoul_result,
+                              unsigned long illegal_value,
+                              unsigned long min_limit,
+                              unsigned long max_limit)
+{
+  sdp_result_e result1 = SDP_SUCCESS;
+  unsigned long value;
+  char* strtoul_end;
+
+  result1 = sdp_get_fmtp_tok(sdp_p, fmtp_ptr, fmtp_name, buf, buf_size, tok);
+  if (result1 != SDP_SUCCESS) return result1;
+
+  errno = 0;
+  value = strtoul(*tok, &strtoul_end, 10);
+
+  if (errno
+      || (*tok == strtoul_end)
+      || (illegal_value != -1UL && value == illegal_value)
+      || (min_limit != -1UL && value < min_limit)
+      || (max_limit != -1UL && value > max_limit)) {
+    sdp_attr_fmtp_invalid_value(sdp_p, fmtp_name, *tok);
+    return SDP_INVALID_PARAMETER;
+  }
+  *strtoul_result = value;
+
+  return SDP_SUCCESS;
+}
+
 
 sdp_result_e sdp_parse_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p,
                                   const char *ptr)
 {
     uint16_t           i;
     uint32_t           mapword;
     uint32_t           bmap;
     uint8_t            low_val;
@@ -598,27 +655,19 @@ sdp_result_e sdp_parse_attr_fmtp (sdp_t 
     fmtp_ptr = src_ptr = temp_ptr;
 
     src_ptr = temp_ptr;
     while (!done) {
       fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "= \t", &result1);
       if (result1 == SDP_SUCCESS) {
         if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[1].name,
                         sdp_fmtp_codec_param[1].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr  = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "annexb");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
+            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "annexb", tmp, sizeof(tmp), &tok);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[0].name,
                             sdp_fmtp_codec_param_val[0].strlen) == 0) {
                 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
                 fmtp_p->annexb_required = TRUE;
                 fmtp_p->annexb = TRUE;
             } else if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[1].name,
                                    sdp_fmtp_codec_param_val[1].strlen) == 0) {
                 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
@@ -628,28 +677,19 @@ sdp_result_e sdp_parse_attr_fmtp (sdp_t 
                 sdp_attr_fmtp_invalid_value(sdp_p, "annexb", tok);
                 SDP_FREE(temp_ptr);
                 return SDP_INVALID_PARAMETER;
             }
             codec_info_found = TRUE;
 
         } else if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[0].name,
                                sdp_fmtp_codec_param[0].strlen) == 0) {
-
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "annexa");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
+            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "annexa", tmp, sizeof(tmp), &tok);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[0].name,
                             sdp_fmtp_codec_param_val[0].strlen) == 0) {
                 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
                 fmtp_p->annexa = TRUE;
                 fmtp_p->annexa_required = TRUE;
             } else if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[1].name,
                                    sdp_fmtp_codec_param_val[1].strlen) == 0) {
                 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
@@ -659,243 +699,100 @@ sdp_result_e sdp_parse_attr_fmtp (sdp_t 
                 sdp_attr_fmtp_invalid_value(sdp_p, "annexa", tok);
                 SDP_FREE(temp_ptr);
                 return SDP_INVALID_PARAMETER;
             }
             codec_info_found = TRUE;
 
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[2].name,
                                sdp_fmtp_codec_param[2].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "bitrate");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > UINT_MAX) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "bitrate", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "bitrate", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
 
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->bitrate = (uint32_t) strtoul_result;
             codec_info_found = TRUE;
 
          } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[41].name,
                                sdp_fmtp_codec_param[41].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "mode");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result > UINT_MAX) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "mode", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "mode", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, -1, -1, UINT_MAX);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
 
             fmtp_p->fmtp_format = SDP_FMTP_MODE;
             fmtp_p->mode = (uint32_t) strtoul_result;
             codec_info_found = TRUE;
 
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[3].name,
                                sdp_fmtp_codec_param[3].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-           fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                sdp_attr_fmtp_no_value(sdp_p, "qcif");
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
-        }
-        tok = tmp;
-        tok++;
-
-        errno = 0;
-        strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-        if (errno || tok == strtoul_end ||
-            strtoul_result < SDP_MIN_CIF_VALUE || strtoul_result > SDP_MAX_CIF_VALUE) {
-            sdp_attr_fmtp_invalid_value(sdp_p, "qcif", tok);
-            SDP_FREE(temp_ptr);
-            return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "qcif", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
 
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->qcif = (uint16_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[4].name,
                                sdp_fmtp_codec_param[4].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                sdp_attr_fmtp_no_value(sdp_p, "cif");
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
-        }
-        tok = tmp;
-        tok++;
-
-        errno = 0;
-        strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-        if (errno || tok == strtoul_end ||
-            strtoul_result < SDP_MIN_CIF_VALUE || strtoul_result > SDP_MAX_CIF_VALUE) {
-            sdp_attr_fmtp_invalid_value(sdp_p, "cif", tok);
-            SDP_FREE(temp_ptr);
-            return SDP_INVALID_PARAMETER;
-        }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cif", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
 
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->cif = (uint16_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[5].name,
                                sdp_fmtp_codec_param[5].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "maxbr");
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
-        }
-        tok = tmp;
-            tok++;
-
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end ||
-                strtoul_result == 0 || strtoul_result > USHRT_MAX) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "maxbr", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "maxbr", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, 0, -1, USHRT_MAX);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
 
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->maxbr = (uint16_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[6].name,
                                sdp_fmtp_codec_param[6].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "sqcif");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-        errno = 0;
-        strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-        if (errno || tok == strtoul_end ||
-            strtoul_result < SDP_MIN_CIF_VALUE || strtoul_result > SDP_MAX_CIF_VALUE) {
-            sdp_attr_fmtp_invalid_value(sdp_p, "sqcif", tok);
-            SDP_FREE(temp_ptr);
-            return SDP_INVALID_PARAMETER;
-        }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "sqcif", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
 
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->sqcif = (uint16_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[7].name,
                                sdp_fmtp_codec_param[7].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "cif4");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-        errno = 0;
-        strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end ||
-                strtoul_result < SDP_MIN_CIF_VALUE || strtoul_result > SDP_MAX_CIF_VALUE) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "cif4", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cif4", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
 
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->cif4 = (uint16_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[8].name,
                                sdp_fmtp_codec_param[8].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "cif16");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-        errno = 0;
-        strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-        if (errno || tok == strtoul_end ||
-            strtoul_result < SDP_MIN_CIF_VALUE || strtoul_result > SDP_MAX_CIF_VALUE) {
-            sdp_attr_fmtp_invalid_value(sdp_p, "cif16", tok);
-            SDP_FREE(temp_ptr);
-            return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cif16", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
 
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->cif16 = (uint16_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else  if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[9].name,
                                sdp_fmtp_codec_param[9].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "custom");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++; temp=PL_strtok_r(tok, ",", &strtok_state);
+            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "custom", tmp, sizeof(tmp), &tok);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+            temp=PL_strtok_r(tok, ",", &strtok_state);
             iter++;
         if (temp) {
             iter=1;
             while (temp != NULL) {
                 errno = 0;
                 strtoul_result = strtoul(temp, &strtoul_end, 10);
 
                 if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX){
@@ -921,29 +818,23 @@ sdp_result_e sdp_parse_attr_fmtp (sdp_t 
                 SDP_FREE(temp_ptr);
                 return SDP_INVALID_PARAMETER;
             }
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->custom_x = custom_x;
             fmtp_p->custom_y = custom_y;
             fmtp_p->custom_mpi = custom_mpi;
             codec_info_found = TRUE;
+
         } else  if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[10].name,
                                sdp_fmtp_codec_param[10].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "par");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++; temp=PL_strtok_r(tok, ":", &strtok_state);
+            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "par", tmp, sizeof(tmp), &tok);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+            temp=PL_strtok_r(tok, ":", &strtok_state);
         if (temp) {
             iter=1;
             /* get par width and par height for the aspect ratio */
             while (temp != NULL) {
                 errno = 0;
                 strtoul_result = strtoul(temp, &strtoul_end, 10);
 
                 if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
@@ -964,29 +855,23 @@ sdp_result_e sdp_parse_attr_fmtp (sdp_t 
                 sdp_attr_fmtp_invalid_value(sdp_p, "par_width or par_height", temp);
                 SDP_FREE(temp_ptr);
                 return SDP_INVALID_PARAMETER;
             }
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->par_width = par_width;
             fmtp_p->par_height = par_height;
             codec_info_found = TRUE;
+
         } else  if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[11].name,
                                sdp_fmtp_codec_param[11].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "cpcf");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++; temp=PL_strtok_r(tok, ".", &strtok_state);
+            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "cpcf", tmp, sizeof(tmp), &tok);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+            temp=PL_strtok_r(tok, ".", &strtok_state);
         if ( temp != NULL  ) {
             errno = 0;
             strtoul_result = strtoul(temp, &strtoul_end, 10);
 
             if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
                 cpcf = 0;
             } else {
                 cpcf = (uint16_t) strtoul_result;
@@ -996,594 +881,303 @@ sdp_result_e sdp_parse_attr_fmtp (sdp_t 
             if (!cpcf) {
                 sdp_attr_fmtp_invalid_value(sdp_p, "cpcf", tok);
                 SDP_FREE(temp_ptr);
                 return SDP_INVALID_PARAMETER;
             }
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->cpcf = cpcf;
             codec_info_found = TRUE;
+
         } else  if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[12].name,
                                sdp_fmtp_codec_param[12].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "bpp");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-        errno = 0;
-        strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-        if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > USHRT_MAX) {
-            sdp_attr_fmtp_invalid_value(sdp_p, "bpp", tok);
-            SDP_FREE(temp_ptr);
-            return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "bpp", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, 0, -1, USHRT_MAX);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
 
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
         fmtp_p->bpp = (uint16_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else  if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[13].name,
                                sdp_fmtp_codec_param[13].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "hrd");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > USHRT_MAX) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "hrd", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "hrd", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, 0, -1, USHRT_MAX);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
 
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->hrd = (uint16_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[14].name,
                                sdp_fmtp_codec_param[14].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "profile");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end ||
-                strtoul_result > SDP_MAX_PROFILE_VALUE) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "profile", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "profile", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, -1, -1, SDP_MAX_PROFILE_VALUE);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
 
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->profile = (short) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[15].name,
                                sdp_fmtp_codec_param[15].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "level");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-        errno = 0;
-        strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-        if (errno || tok == strtoul_end ||
-            strtoul_result > SDP_MAX_LEVEL_VALUE) {
-            sdp_attr_fmtp_invalid_value(sdp_p, "level", tok);
-            SDP_FREE(temp_ptr);
-            return SDP_INVALID_PARAMETER;
-        }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "level", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, -1, -1, SDP_MAX_LEVEL_VALUE);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
 
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->level = (short) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[16].name,
                                sdp_fmtp_codec_param[16].strlen) == 0) {
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->is_interlace = TRUE;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[17].name,
                                sdp_fmtp_codec_param[17].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "profile_level_id");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
+            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "profile_level_id", tmp, sizeof(tmp), &tok);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             sstrncpy(fmtp_p->profile_level_id , tok, sizeof(fmtp_p->profile_level_id));
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[18].name,
                                sdp_fmtp_codec_param[18].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "parameter_sets");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
+            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "parameter_sets", tmp, sizeof(tmp), &tok);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             sstrncpy(fmtp_p->parameter_sets , tok, sizeof(fmtp_p->parameter_sets));
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[19].name,
                                sdp_fmtp_codec_param[19].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "packetization_mode");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result > 2) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "packetization_mode", tok);
-                sdp_p->conf_p->num_invalid_param++;
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "packetization_mode", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, -1, -1, 2);
+            // this one is different for some reason. Most others don't increment
+            // the num_invalid_param field. (mjf)
+            if (result1 == SDP_INVALID_PARAMETER) { sdp_p->conf_p->num_invalid_param++; }
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
 
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->packetization_mode = (int16_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[20].name,
                                sdp_fmtp_codec_param[20].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "interleaving_depth");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > USHRT_MAX) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "interleaving_depth", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "interleaving_depth", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, 0, -1, USHRT_MAX);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
 
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->interleaving_depth = (uint16_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[21].name,
                                sdp_fmtp_codec_param[21].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "deint_buf");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
+            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "deint_buf", tmp, sizeof(tmp), &tok);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
                 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
                 fmtp_p->deint_buf_req = (uint32_t) l_val;
                 fmtp_p->flag |= SDP_DEINT_BUF_REQ_FLAG;
                 codec_info_found = TRUE;
             } else {
                 sdp_attr_fmtp_invalid_value(sdp_p, "deint_buf_req", tok);
                 SDP_FREE(temp_ptr);
                 return SDP_INVALID_PARAMETER;
             }
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[22].name,
                                sdp_fmtp_codec_param[22].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "max_don_diff");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > UINT_MAX) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "max_don_diff", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_don_diff", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
 
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->max_don_diff = (uint32_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[23].name,
                                sdp_fmtp_codec_param[23].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "init_buf_time");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
+            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "init_buf_time", tmp, sizeof(tmp), &tok);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
                 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
                 fmtp_p->init_buf_time = (uint32_t) l_val;
                 fmtp_p->flag |= SDP_INIT_BUF_TIME_FLAG;
                 codec_info_found = TRUE;
             } else {
                 sdp_attr_fmtp_invalid_value(sdp_p, "init_buf_time", tok);
                 SDP_FREE(temp_ptr);
                 return SDP_INVALID_PARAMETER;
             }
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[24].name,
                                sdp_fmtp_codec_param[24].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "max_mbps");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > UINT_MAX) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "max_mbps", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_mbps", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
 
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
         fmtp_p->max_mbps = (uint32_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[25].name,
                                sdp_fmtp_codec_param[25].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "max-fs");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > UINT_MAX) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "max-fs", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max-fs", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->max_fs = (uint32_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[26].name,
                                sdp_fmtp_codec_param[26].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "max_cbp");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > UINT_MAX) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "max_cpb", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_cbp", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->max_cpb = (uint32_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[27].name,
                                sdp_fmtp_codec_param[27].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "max_dpb");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > UINT_MAX) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "max_dpb", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_dpb", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->max_dpb = (uint32_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[28].name,
                                sdp_fmtp_codec_param[28].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "max_br");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > UINT_MAX) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "max_br", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_br", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->max_br = (uint32_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[29].name,
                                sdp_fmtp_codec_param[29].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "redundant_pic_cap");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-        errno = 0;
-        strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-        if (!errno && tok != strtoul_end && strtoul_result == 1) {
-            fmtp_p->redundant_pic_cap = TRUE;
-        } else {
-            fmtp_p->redundant_pic_cap = FALSE;
-        }
-
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "redundant_pic_cap", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, 0, -1, 1);
+            fmtp_p->redundant_pic_cap = (result1 == SDP_SUCCESS);
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[30].name,
                                sdp_fmtp_codec_param[30].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "deint_buf_cap");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
+            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "deint_buf_cap", tmp, sizeof(tmp), &tok);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
                 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
                 fmtp_p->deint_buf_cap = (uint32_t) l_val;
                 fmtp_p->flag |= SDP_DEINT_BUF_CAP_FLAG;
                 codec_info_found = TRUE;
             } else {
                 sdp_attr_fmtp_invalid_value(sdp_p, "deint_buf_cap", tok);
                 SDP_FREE(temp_ptr);
                 return SDP_INVALID_PARAMETER;
             }
+
         }  else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[31].name,
                                sdp_fmtp_codec_param[31].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "max_rcmd_nalu_size");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
+            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "max_rcmd_nalu_size", tmp, sizeof(tmp), &tok);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
                 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
                 fmtp_p->max_rcmd_nalu_size = (uint32_t) l_val;
                 fmtp_p->flag |= SDP_MAX_RCMD_NALU_SIZE_FLAG;
                 codec_info_found = TRUE;
             } else {
                 sdp_attr_fmtp_invalid_value(sdp_p, "max_rcmd_nalu_size", tok);
                 SDP_FREE(temp_ptr);
                 return SDP_INVALID_PARAMETER;
             }
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[32].name,
                                sdp_fmtp_codec_param[32].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "parameter_add");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result > 1) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "parameter_add", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "parameter_add", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, 0, -1, 1);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->parameter_add = (uint16_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[33].name,
                                sdp_fmtp_codec_param[33].strlen) == 0) {
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->annex_d = TRUE;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[34].name,
                                sdp_fmtp_codec_param[34].strlen) == 0) {
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->annex_f = TRUE;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[35].name,
                                sdp_fmtp_codec_param[35].strlen) == 0) {
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->annex_i = TRUE;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[36].name,
                                sdp_fmtp_codec_param[36].strlen) == 0) {
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->annex_j = TRUE;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[37].name,
                                sdp_fmtp_codec_param[36].strlen) == 0) {
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->annex_t = TRUE;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[38].name,
                              sdp_fmtp_codec_param[38].strlen) == 0) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                    if (result1 != SDP_SUCCESS) {
-                        sdp_attr_fmtp_no_value(sdp_p, "annex_k");
-                        SDP_FREE(temp_ptr);
-                        return SDP_INVALID_PARAMETER;
-                    }
-                }
-                tok = tmp;
-                tok++;
-
-                errno = 0;
-                strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-                if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > USHRT_MAX) {
-                    sdp_attr_fmtp_invalid_value(sdp_p, "annex_k", tok);
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "annex_k", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, 0, -1, USHRT_MAX);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
                 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
                 fmtp_p->annex_k_val = (uint16_t) strtoul_result;
                 codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[39].name,
                                sdp_fmtp_codec_param[39].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "annex_n");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > USHRT_MAX) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "annex_n", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "annex_n", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, 0, -1, USHRT_MAX);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->annex_n_val = (uint16_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[40].name,
                                sdp_fmtp_codec_param[40].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "annex_p");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
+            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "annex_p", tmp, sizeof(tmp), &tok);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             fmtp_p->annex_p_val_picture_resize = 0;
             fmtp_p->annex_p_val_warp = 0;
-            tok = tmp;
-            tok++; temp = PL_strtok_r(tok, ",", &strtok_state);
+            temp = PL_strtok_r(tok, ",", &strtok_state);
             if (temp) {
                 iter=1;
                 while (temp != NULL) {
                     errno = 0;
                     strtoul_result = strtoul(temp, &strtoul_end, 10);
 
                     if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
                         break;
@@ -1596,233 +1190,105 @@ sdp_result_e sdp_parse_attr_fmtp (sdp_t 
 
                     temp = PL_strtok_r(NULL, ",", &strtok_state);
                     iter++;
                 }
             }
 
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[42].name,
                                sdp_fmtp_codec_param[42].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "level_asymmetry_allowed");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result > SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "level_asymmetry_allowed", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "level_asymmetry_allowed", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, -1, -1, SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->level_asymmetry_allowed = (int) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[43].name,
                                    sdp_fmtp_codec_param[43].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                    fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "maxaveragebitrate");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > UINT_MAX) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "maxaveragebitrate", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "maxaveragebitrate", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->maxaveragebitrate = (uint32_t) strtoul_result;
             codec_info_found = TRUE;
 
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[44].name,
                                    sdp_fmtp_codec_param[44].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                    fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "usedtx");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result > 1) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "usedtx", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "usedtx", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, -1, -1, 1);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->usedtx = (uint16_t) strtoul_result;
             codec_info_found = TRUE;
 
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[45].name,
                                    sdp_fmtp_codec_param[45].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                    fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "stereo");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-            errno = 0;
-
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result > 1) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "stereo", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "stereo", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, -1, -1, 1);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->stereo = (uint16_t) strtoul_result;
             codec_info_found = TRUE;
 
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[46].name,
                                    sdp_fmtp_codec_param[46].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                    fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "useinbandfec");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-            errno = 0;
-
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result > 1) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "useinbandfec", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "useinbandfec", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, -1, -1, 1);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->useinbandfec = (uint16_t) strtoul_result;
             codec_info_found = TRUE;
 
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[47].name,
                                        sdp_fmtp_codec_param[47].strlen) == 0) {
-                    fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-                    if (result1 != SDP_SUCCESS) {
-                        fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                        if (result1 != SDP_SUCCESS) {
-                            sdp_attr_fmtp_no_value(sdp_p, "maxcodedaudiobandwidth");
-                            sdp_p->conf_p->num_invalid_param++;
-                            SDP_FREE(temp_ptr);
-                            return SDP_INVALID_PARAMETER;
-                        }
-                    }
-                    tok = tmp;
-                    tok++;
+            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "maxcodedaudiobandwidth", tmp, sizeof(tmp), &tok);
+            // this one is different for some reason. Most others don't increment
+            // the num_invalid_param field. (mjf)
+            if (result1 == SDP_INVALID_PARAMETER) { sdp_p->conf_p->num_invalid_param++; }
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
                     fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
                     sstrncpy(fmtp_p->maxcodedaudiobandwidth , tok, sizeof(fmtp_p->maxcodedaudiobandwidth));
                     codec_info_found = TRUE;
 
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[48].name,
                                    sdp_fmtp_codec_param[48].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "cbr");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-            errno = 0;
-
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result > 1) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "cbr", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cbr", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, -1, -1, 1);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->cbr = (uint16_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[49].name,
                                    sdp_fmtp_codec_param[49].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t",
-                                         &result1);
-            if (result1 != SDP_SUCCESS) {
-                fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp),
-                                             " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "max-fr");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-            if (errno || tok == strtoul_end || strtoul_result == 0 ||
-                strtoul_result > UINT_MAX) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "max-fr", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max-fr", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->max_fr = (uint32_t) strtoul_result;
             codec_info_found = TRUE;
+
         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[50].name,
                                    sdp_fmtp_codec_param[50].strlen) == 0) {
-            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
-            if (result1 != SDP_SUCCESS) {
-                    fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
-                if (result1 != SDP_SUCCESS) {
-                    sdp_attr_fmtp_no_value(sdp_p, "maxplaybackrate");
-                    SDP_FREE(temp_ptr);
-                    return SDP_INVALID_PARAMETER;
-                }
-            }
-            tok = tmp;
-            tok++;
-            errno = 0;
-            strtoul_result = strtoul(tok, &strtoul_end, 10);
-
-            if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > UINT_MAX) {
-                sdp_attr_fmtp_invalid_value(sdp_p, "maxplaybackrate", tok);
-                SDP_FREE(temp_ptr);
-                return SDP_INVALID_PARAMETER;
-            }
+            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "maxplaybackrate", tmp, sizeof(tmp),
+                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
+            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
             fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
             fmtp_p->maxplaybackrate = (uint32_t) strtoul_result;
             codec_info_found = TRUE;
 
         } else if (fmtp_ptr != NULL && *fmtp_ptr == '\n') {
             temp=PL_strtok_r(tmp, ";", &strtok_state);
             if (temp) {
                 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
--- a/media/webrtc/signaling/src/sdp/sipcc/sdp_attr_access.c
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_attr_access.c
@@ -2404,17 +2404,17 @@ sdp_result_e sdp_attr_copy_fmtp_ranges (
 /* Function:    sdp_attr_get_fmtp_mode
  * Description: Gets the value of the fmtp attribute mode parameter
  *              for the given attribute.
  * Parameters:  sdp_p     The SDP handle returned by sdp_init_description.
  *              level       The level to check for the attribute.
  *              cap_num     The capability number associated with the
  *                          attribute if any.  If none, should be zero.
  *              payload_type payload type.
- * Returns:     mode value
+ * Returns:     mode value or zero if mode attribute not found
  */
 uint32_t sdp_attr_get_fmtp_mode_for_payload_type (sdp_t *sdp_p, uint16_t level,
                                              uint8_t cap_num, uint32_t payload_type)
 {
     uint16_t          num_a_lines = 0;
     int          i;
     sdp_attr_t  *attr_p;
 
--- a/media/webrtc/signaling/test/sdp_unittests.cpp
+++ b/media/webrtc/signaling/test/sdp_unittests.cpp
@@ -818,29 +818,644 @@ TEST_F(SdpTest, parseExtMap) {
     "a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n");
   ASSERT_STREQ(sdp_attr_get_extmap_uri(sdp_ptr_, 1, 1),
             SDP_EXTMAP_AUDIO_LEVEL);
   ASSERT_EQ(sdp_attr_get_extmap_id(sdp_ptr_, 1, 1),
             1);
 
 }
 
+TEST_F(SdpTest, parseFmtpBitrate) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 bitrate=400\r\n");
+  ASSERT_EQ(400, sdp_attr_get_fmtp_bitrate_type(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpBitrateWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 bitrate=0\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_bitrate_type(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpBitrateWith32001) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 bitrate=32001\r\n");
+  ASSERT_EQ(32001, sdp_attr_get_fmtp_bitrate_type(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpBitrateWith4294967296) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 bitrate=4294967296\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_bitrate_type(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpMode) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 mode=200\r\n");
+  ASSERT_EQ(200U, sdp_attr_get_fmtp_mode_for_payload_type(sdp_ptr_, 1, 0, 120));
+}
+
+TEST_F(SdpTest, parseFmtpModeWith4294967295) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 mode=4294967295\r\n");
+  ASSERT_EQ(4294967295, sdp_attr_get_fmtp_mode_for_payload_type(sdp_ptr_, 1, 0, 120));
+}
+
+TEST_F(SdpTest, parseFmtpModeWith4294967296) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 mode=4294967296\r\n");
+  // returns 0 if not found
+  ASSERT_EQ(0U, sdp_attr_get_fmtp_mode_for_payload_type(sdp_ptr_, 1, 0, 120));
+}
+
+TEST_F(SdpTest, parseFmtpQcif) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 qcif=20\r\n");
+  ASSERT_EQ(20, sdp_attr_get_fmtp_qcif(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpQcifWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 qcif=0\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_qcif(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpQcifWith33) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 qcif=33\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_qcif(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpCif) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 cif=11\r\n");
+  ASSERT_EQ(11, sdp_attr_get_fmtp_cif(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpCifWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 cif=0\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_cif(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpCifWith33) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 cif=33\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_cif(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpMaxbr) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 maxbr=21\r\n");
+  ASSERT_EQ(21, sdp_attr_get_fmtp_maxbr(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpMaxbrWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 maxbr=0\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_maxbr(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpMaxbrWith65536) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 maxbr=65536\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_maxbr(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpSqcif) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 sqcif=6\r\n");
+  ASSERT_EQ(6, sdp_attr_get_fmtp_sqcif(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpSqcifWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 sqcif=0\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_sqcif(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpSqcifWith33) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 sqcif=33\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_sqcif(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpCif4) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 cif4=11\r\n");
+  ASSERT_EQ(11, sdp_attr_get_fmtp_cif4(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpCif4With0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 cif4=0\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_cif4(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpCif4With33) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 cif4=33\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_cif4(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpCif16) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 cif16=11\r\n");
+  ASSERT_EQ(11, sdp_attr_get_fmtp_cif16(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpCif16With0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 cif16=0\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_cif16(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpCif16With33) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 cif16=33\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_cif16(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpBpp) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 bpp=7\r\n");
+  ASSERT_EQ(7, sdp_attr_get_fmtp_bpp(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpBppWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 bpp=0\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_bpp(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpBppWith65536) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 bpp=65536\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_bpp(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpHrd) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 hrd=800\r\n");
+  ASSERT_EQ(800, sdp_attr_get_fmtp_hrd(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpHrdWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 hrd=0\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_hrd(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpHrdWith65536) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 hrd=65536\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_hrd(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpProfile) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 profile=4\r\n");
+  ASSERT_EQ(4, sdp_attr_get_fmtp_profile(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpProfileWith11) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 profile=11\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_profile(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpLevel) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 level=56\r\n");
+  ASSERT_EQ(56, sdp_attr_get_fmtp_level(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpLevelWith101) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 level=101\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_level(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpPacketizationMode) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 packetization-mode=1\r\n");
+  uint16_t packetizationMode;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_pack_mode(sdp_ptr_, 1, 0, 1, &packetizationMode));
+  ASSERT_EQ(1, packetizationMode);
+}
+
+TEST_F(SdpTest, parseFmtpPacketizationModeWith3) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 packetization-mode=3\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_pack_mode(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpInterleavingDepth) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 sprop-interleaving-depth=566\r\n");
+  uint16_t interleavingDepth;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_interleaving_depth(sdp_ptr_, 1, 0, 1, &interleavingDepth));
+  ASSERT_EQ(566, interleavingDepth);
+}
+
+TEST_F(SdpTest, parseFmtpInterleavingDepthWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 sprop-interleaving-depth=0\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_interleaving_depth(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpInterleavingDepthWith65536) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 sprop-interleaving-depth=65536\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_interleaving_depth(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpDeintBuf) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 sprop-deint-buf-req=4294967295\r\n");
+  uint32_t deintBuf;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_deint_buf_req(sdp_ptr_, 1, 0, 1, &deintBuf));
+  ASSERT_EQ(4294967295, deintBuf);
+}
+
+TEST_F(SdpTest, parseFmtpDeintBufWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 sprop-deint-buf-req=0\r\n");
+  uint32_t deintBuf;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_deint_buf_req(sdp_ptr_, 1, 0, 1, &deintBuf));
+  ASSERT_EQ(0U, deintBuf);
+}
+
+TEST_F(SdpTest, parseFmtpDeintBufWith4294967296) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 sprop-deint-buf-req=4294967296\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_deint_buf_req(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpMaxDonDiff) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 sprop-max-don-diff=5678\r\n");
+  uint32_t maxDonDiff;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_max_don_diff(sdp_ptr_, 1, 0, 1, &maxDonDiff));
+  ASSERT_EQ(5678U, maxDonDiff);
+}
+
+TEST_F(SdpTest, parseFmtpMaxDonDiffWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 sprop-max-don-diff=0\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_max_don_diff(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpMaxDonDiffWith4294967296) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 sprop-max-don-diff=4294967296\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_max_don_diff(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpInitBufTime) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 sprop-init-buf-time=4294967295\r\n");
+  uint32_t initBufTime;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_init_buf_time(sdp_ptr_, 1, 0, 1, &initBufTime));
+  ASSERT_EQ(4294967295, initBufTime);
+}
+
+TEST_F(SdpTest, parseFmtpInitBufTimeWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 sprop-init-buf-time=0\r\n");
+  uint32_t initBufTime;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_init_buf_time(sdp_ptr_, 1, 0, 1, &initBufTime));
+  ASSERT_EQ(0U, initBufTime);
+}
+
+TEST_F(SdpTest, parseFmtpInitBufTimeWith4294967296) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 sprop-init-buf-time=4294967296\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_init_buf_time(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpMaxMbps) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-mbps=46789\r\n");
+  uint32_t maxMpbs;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_max_mbps(sdp_ptr_, 1, 0, 1, &maxMpbs));
+  ASSERT_EQ(46789U, maxMpbs);
+}
+
+TEST_F(SdpTest, parseFmtpMaxMbpsWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-mbps=0\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_max_mbps(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpMaxMbpsWith4294967296) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-mbps=4294967296\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_max_mbps(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpMaxCpb) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-cpb=47891\r\n");
+  uint32_t maxCpb;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_max_cpb(sdp_ptr_, 1, 0, 1, &maxCpb));
+  ASSERT_EQ(47891U, maxCpb);
+}
+
+TEST_F(SdpTest, parseFmtpMaxCpbWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-cpb=0\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_max_cpb(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpMaxCpbWith4294967296) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-cpb=4294967296\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_max_cpb(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpMaxDpb) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-dpb=47892\r\n");
+  uint32_t maxDpb;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_max_dpb(sdp_ptr_, 1, 0, 1, &maxDpb));
+  ASSERT_EQ(47892U, maxDpb);
+}
+
+TEST_F(SdpTest, parseFmtpMaxDpbWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-dpb=0\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_max_dpb(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpMaxDpbWith4294967296) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-dpb=4294967296\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_max_dpb(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpMaxBr) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-br=47893\r\n");
+  uint32_t maxBr;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_max_br(sdp_ptr_, 1, 0, 1, &maxBr));
+  ASSERT_EQ(47893U, maxBr);
+}
+
+TEST_F(SdpTest, parseFmtpMaxBrWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-br=0\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_max_br(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpMaxBrWith4294967296) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-br=4294967296\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_max_br(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpRedundantPicCap) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 redundant-pic-cap=1\r\n");
+  ASSERT_EQ(1, sdp_attr_fmtp_is_redundant_pic_cap(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpRedundantPicCapWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 redundant-pic-cap=0\r\n");
+  ASSERT_EQ(0, sdp_attr_fmtp_is_redundant_pic_cap(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpRedundantPicCapWith2) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 redundant-pic-cap=2\r\n");
+  ASSERT_EQ(0, sdp_attr_fmtp_is_redundant_pic_cap(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpDeintBufCap) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 deint-buf-cap=4294967295\r\n");
+  uint32_t deintBufCap;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_deint_buf_cap(sdp_ptr_, 1, 0, 1, &deintBufCap));
+  ASSERT_EQ(4294967295, deintBufCap);
+}
+
+TEST_F(SdpTest, parseFmtpDeintBufCapWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 deint-buf-cap=0\r\n");
+  uint32_t deintBufCap;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_deint_buf_cap(sdp_ptr_, 1, 0, 1, &deintBufCap));
+  ASSERT_EQ(0U, deintBufCap);
+}
+
+TEST_F(SdpTest, parseFmtpDeintBufCapWith4294967296) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 deint-buf-cap=4294967296\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_deint_buf_cap(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpMaxRcmdNaluSize) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-rcmd-nalu-size=4294967295\r\n");
+  uint32_t maxRcmdNaluSize;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_max_rcmd_nalu_size(sdp_ptr_, 1, 0, 1, &maxRcmdNaluSize));
+  ASSERT_EQ(4294967295, maxRcmdNaluSize);
+}
+
+TEST_F(SdpTest, parseFmtpMaxRcmdNaluSizeWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-rcmd-nalu-size=0\r\n");
+  uint32_t maxRcmdNaluSize;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_max_rcmd_nalu_size(sdp_ptr_, 1, 0, 1, &maxRcmdNaluSize));
+  ASSERT_EQ(0U, maxRcmdNaluSize);
+}
+
+TEST_F(SdpTest, parseFmtpMaxRcmdNaluSizeWith4294967296) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-rcmd-nalu-size=4294967296\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_max_rcmd_nalu_size(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpParameterAdd) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 parameter-add=1\r\n");
+  ASSERT_EQ(1, sdp_attr_fmtp_is_parameter_add(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpParameterAddWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 parameter-add=0\r\n");
+  ASSERT_EQ(0, sdp_attr_fmtp_is_parameter_add(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpParameterAddWith2) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 parameter-add=2\r\n");
+  ASSERT_EQ(0, sdp_attr_fmtp_is_parameter_add(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpAnnexK) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 K=566\r\n");
+  ASSERT_EQ(566, sdp_attr_get_fmtp_annex_k_val(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpAnnexKWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 K=0\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_annex_k_val(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpAnnexKWith65536) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 K=65536\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_annex_k_val(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpAnnexN) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 N=4567\r\n");
+  ASSERT_EQ(4567, sdp_attr_get_fmtp_annex_n_val(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpAnnexNWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 N=0\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_annex_n_val(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpAnnexNWith65536) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 N=65536\r\n");
+  ASSERT_EQ(SDP_INVALID_VALUE, sdp_attr_get_fmtp_annex_n_val(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpAnnexP) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 P=5678,2\r\n");
+  ASSERT_EQ(5678, sdp_attr_get_fmtp_annex_p_picture_resize(sdp_ptr_, 1, 0, 1));
+  ASSERT_EQ(2, sdp_attr_get_fmtp_annex_p_warp(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpAnnexPWithResize0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 P=0,3\r\n");
+  ASSERT_EQ(0, sdp_attr_get_fmtp_annex_p_picture_resize(sdp_ptr_, 1, 0, 1));
+  ASSERT_EQ(3, sdp_attr_get_fmtp_annex_p_warp(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpAnnexPWithResize65536) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 P=65536,4\r\n");
+  ASSERT_EQ(0, sdp_attr_get_fmtp_annex_p_picture_resize(sdp_ptr_, 1, 0, 1));
+  // if the first fails, the second will too.  Both default to 0 on failure.
+  ASSERT_EQ(0, sdp_attr_get_fmtp_annex_p_warp(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpAnnexPWithWarp65536) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 P=346,65536\r\n");
+  ASSERT_EQ(346, sdp_attr_get_fmtp_annex_p_picture_resize(sdp_ptr_, 1, 0, 1));
+  ASSERT_EQ(0, sdp_attr_get_fmtp_annex_p_warp(sdp_ptr_, 1, 0, 1));
+}
+
+TEST_F(SdpTest, parseFmtpLevelAsymmetryAllowed) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 level-asymmetry-allowed=1\r\n");
+
+  uint16_t levelAsymmetryAllowed;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_level_asymmetry_allowed(sdp_ptr_, 1, 0, 1, &levelAsymmetryAllowed));
+  ASSERT_EQ(1U, levelAsymmetryAllowed);
+}
+
+TEST_F(SdpTest, parseFmtpLevelAsymmetryAllowedWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 level-asymmetry-allowed=0\r\n");
+  uint16_t levelAsymmetryAllowed;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_level_asymmetry_allowed(sdp_ptr_, 1, 0, 1, &levelAsymmetryAllowed));
+  ASSERT_EQ(0U, levelAsymmetryAllowed);
+}
+
+TEST_F(SdpTest, parseFmtpLevelAsymmetryAllowedWith2) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 level-asymmetry-allowed=2\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_level_asymmetry_allowed(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpMaxAverageBitrate) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 maxaveragebitrate=47893\r\n");
+  uint32_t maxAverageBitrate;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_max_average_bitrate(sdp_ptr_, 1, 0, 1, &maxAverageBitrate));
+  ASSERT_EQ(47893U, maxAverageBitrate);
+}
+
+TEST_F(SdpTest, parseFmtpMaxAverageBitrateWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 maxaveragebitrate=0\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_max_average_bitrate(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpMaxAverageBitrateWith4294967296) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 maxaveragebitrate=4294967296\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_max_average_bitrate(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpUsedTx) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 usedtx=1\r\n");
+  tinybool usedTx;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_usedtx(sdp_ptr_, 1, 0, 1, &usedTx));
+  ASSERT_EQ(1, usedTx);
+}
+
+TEST_F(SdpTest, parseFmtpUsedTxWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 usedtx=0\r\n");
+  tinybool usedTx;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_usedtx(sdp_ptr_, 1, 0, 1, &usedTx));
+  ASSERT_EQ(0, usedTx);
+}
+
+TEST_F(SdpTest, parseFmtpUsedTxWith2) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 usedtx=2\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_usedtx(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpStereo) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 stereo=1\r\n");
+  tinybool stereo;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_stereo(sdp_ptr_, 1, 0, 1, &stereo));
+  ASSERT_EQ(1, stereo);
+}
+
+TEST_F(SdpTest, parseFmtpStereoWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 stereo=0\r\n");
+  tinybool stereo;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_stereo(sdp_ptr_, 1, 0, 1, &stereo));
+  ASSERT_EQ(0, stereo);
+}
+
+TEST_F(SdpTest, parseFmtpStereoWith2) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 stereo=2\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_stereo(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpUseInBandFec) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 useinbandfec=1\r\n");
+  tinybool useInbandFec;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_useinbandfec(sdp_ptr_, 1, 0, 1, &useInbandFec));
+  ASSERT_EQ(1, useInbandFec);
+}
+
+TEST_F(SdpTest, parseFmtpUseInBandWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 useinbandfec=0\r\n");
+  tinybool useInbandFec;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_useinbandfec(sdp_ptr_, 1, 0, 1, &useInbandFec));
+  ASSERT_EQ(0, useInbandFec);
+}
+
+TEST_F(SdpTest, parseFmtpUseInBandWith2) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 useinbandfec=2\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_useinbandfec(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpMaxCodedAudioBandwidth) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 maxcodedaudiobandwidth=abcdefg\r\n");
+  char* maxCodedAudioBandwith = sdp_attr_get_fmtp_maxcodedaudiobandwidth(sdp_ptr_, 1, 0, 1);
+  ASSERT_EQ(0, strcmp("abcdefg", maxCodedAudioBandwith));
+}
+
+TEST_F(SdpTest, parseFmtpMaxCodedAudioBandwidthBad) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 maxcodedaudiobandwidth=\r\n");
+  char* maxCodedAudioBandwith = sdp_attr_get_fmtp_maxcodedaudiobandwidth(sdp_ptr_, 1, 0, 1);
+  ASSERT_EQ(0, *maxCodedAudioBandwith);
+}
+
+TEST_F(SdpTest, parseFmtpCbr) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 cbr=1\r\n");
+  tinybool cbr;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_cbr(sdp_ptr_, 1, 0, 1, &cbr));
+  ASSERT_EQ(1, cbr);
+}
+
+TEST_F(SdpTest, parseFmtpCbrWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 cbr=0\r\n");
+  tinybool cbr;
+  ASSERT_EQ(SDP_SUCCESS, sdp_attr_get_fmtp_cbr(sdp_ptr_, 1, 0, 1, &cbr));
+  ASSERT_EQ(0, cbr);
+}
+
+TEST_F(SdpTest, parseFmtpCbrWith2) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 cbr=2\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_cbr(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpMaxPlaybackRate) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 maxplaybackrate=47900\r\n");
+  sdp_attr_t *attr_p = sdp_find_attr(sdp_ptr_, 1, 0, SDP_ATTR_FMTP, 1);
+  ASSERT_NE(NULL, attr_p);
+  ASSERT_EQ(47900U, attr_p->attr.fmtp.maxplaybackrate);
+}
+
+TEST_F(SdpTest, parseFmtpMaxPlaybackRateWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 maxplaybackrate=0\r\n");
+  sdp_attr_t *attr_p = sdp_find_attr(sdp_ptr_, 1, 0, SDP_ATTR_FMTP, 1);
+  ASSERT_EQ(NULL, attr_p);
+}
+
+TEST_F(SdpTest, parseFmtpMaxPlaybackRateWith4294967296) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 maxplaybackrate=4294967296\r\n");
+  sdp_attr_t *attr_p = sdp_find_attr(sdp_ptr_, 1, 0, SDP_ATTR_FMTP, 1);
+  ASSERT_EQ(NULL, attr_p);
+}
+
 TEST_F(SdpTest, parseFmtpMaxFs) {
   uint32_t val = 0;
   ParseSdp(kVideoSdp + "a=fmtp:120 max-fs=300;max-fr=30\r\n");
   ASSERT_EQ(sdp_attr_get_fmtp_max_fs(sdp_ptr_, 1, 0, 1, &val), SDP_SUCCESS);
   ASSERT_EQ(val, 300U);
 }
+TEST_F(SdpTest, parseFmtpMaxFsWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-fs=0\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_max_fs(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpMaxFsWith4294967296) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-fs=4294967296\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_max_fs(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
 TEST_F(SdpTest, parseFmtpMaxFr) {
   uint32_t val = 0;
   ParseSdp(kVideoSdp + "a=fmtp:120 max-fs=300;max-fr=30\r\n");
   ASSERT_EQ(sdp_attr_get_fmtp_max_fr(sdp_ptr_, 1, 0, 1, &val), SDP_SUCCESS);
   ASSERT_EQ(val, 30U);
 }
 
+TEST_F(SdpTest, parseFmtpMaxFrWith0) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-fr=0\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_max_fr(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
+TEST_F(SdpTest, parseFmtpMaxFrWith4294967296) {
+  ParseSdp(kVideoSdp + "a=fmtp:120 max-fr=4294967296\r\n");
+  ASSERT_EQ(SDP_INVALID_PARAMETER, sdp_attr_get_fmtp_max_fr(sdp_ptr_, 1, 0, 1, nullptr));
+}
+
 TEST_F(SdpTest, addFmtpMaxFs) {
   InitLocalSdp();
   int level = AddNewMedia(SDP_MEDIA_VIDEO);
   AddNewFmtpMaxFs(level, 300);
   std::string body = SerializeSdp();
   ASSERT_NE(body.find("a=fmtp:120 max-fs=300\r\n"), std::string::npos);
 }