// RFC-4566 SDP // 6. SDP Attributes (p30) // a=fmtp: #include "sdp-a-fmtp.h" #include #include #include #if defined(OS_WINDOWS) #define strncasecmp _strnicmp #endif // RFC6184 RTP Payload Format for H.264 Video // m=video 49170 RTP/AVP 98 // a=rtpmap:98 H264/90000 // a=fmtp:98 profile-level-id=42A01E; // packetization-mode=1; // sprop-parameter-sets= int sdp_a_fmtp_h264(const char* fmtp, int *format, struct sdp_a_fmtp_h264_t *h264) { size_t nc, vc; const char *p1, *p2; const char *p = fmtp; // payload type *format = atoi(p); p1 = strchr(p, ' '); if(!p1 || ' ' != *p1) return -1; h264->flags = 0; assert(' ' == *p1); p = p1 + 1; while(*p) { p1 = strchr(p, '='); if(!p1 || '=' != *p1) return -1; p2 = strchr(p1+1, ';'); if(!p2) p2 = p1 + strlen(p1); while(' ' == *p) p++; // skip space nc = (size_t)(p1 - p); // ptrdiff_t to size_t vc = (size_t)(p2 - p1 - 1); // ptrdiff_t to size_t switch(*p) { case 'p': // profile-level-id // packetization-mode if(0 == strncasecmp("profile-level-id", p, nc)) { if(6 != vc) return -1; h264->flags |= SDP_A_FMTP_H264_PROFILE_LEVEL_ID; memcpy(h264->profile_level_id, p1+1, 6); h264->profile_level_id[6] = '\0'; } else if(0 == strncasecmp("packetization-mode", p, nc)) { h264->flags |= SDP_A_FMTP_H264_PACKETIZATION_MODE; h264->packetization_mode = atoi(p1+1); } break; case 'm': // max-recv-level // max-mbps // max-smbps // max-fs // max-cbp // max-dbp // max-br // max-rcmd-nalu-size if(0 == strncasecmp("max-recv-level", p, nc)) { h264->flags |= SDP_A_FMTP_H264_MAX_RECV_LEVEL; h264->max_recv_level = atoi(p1+1); } else if(0 == strncasecmp("max-mbps", p, nc)) { h264->flags |= SDP_A_FMTP_H264_MAX_MBPS; h264->max_mbps = atoi(p1+1); } else if(0 == strncasecmp("max-smbps", p, nc)) { h264->flags |= SDP_A_FMTP_H264_MAX_SMBPS; h264->max_smbps = atoi(p1+1); } else if(0 == strncasecmp("max-fs", p, nc)) { h264->flags |= SDP_A_FMTP_H264_MAX_FS; h264->max_fs = atoi(p1+1); } else if(0 == strncasecmp("max-cbp", p, nc)) { h264->flags |= SDP_A_FMTP_H264_MAX_CPB; h264->max_cpb = atoi(p1+1); } else if(0 == strncasecmp("max-dbp", p, nc)) { h264->flags |= SDP_A_FMTP_H264_MAX_DPB; h264->max_dpb = atoi(p1+1); } else if(0 == strncasecmp("max-br", p, nc)) { h264->flags |= SDP_A_FMTP_H264_MAX_BR; h264->max_br = atoi(p1+1); } else if(0 == strncasecmp("max-rcmd-nalu-size", p, nc)) { h264->flags |= SDP_A_FMTP_H264_MAX_RCMD_NALU_SIZE; h264->max_rcmd_nalu_size = (unsigned int)atoi(p1+1); } break; case 's': // sprop-parameter-sets // sprop-level-parameter-sets // sprop-deint-buf-req // sprop-interleaving-depth // sprop-max-don-diff // sprop-init-buf-time // sar-understood // sar-supported if(0 == strncasecmp("sprop-parameter-sets", p, nc)) { if(vc >= sizeof(h264->sprop_parameter_sets)) return -1; h264->flags |= SDP_A_FMTP_H264_SPROP_PARAMETER_SETS; memcpy(h264->sprop_parameter_sets, p1+1, vc); h264->sprop_parameter_sets[vc] = '\0'; } else if(0 == strncasecmp("sprop-level-parameter-sets", p, nc)) { if(vc >= sizeof(h264->sprop_level_parameter_sets)) return -1; h264->flags |= SDP_A_FMTP_H264_SPROP_LEVEL_PARAMETER_SETS; memcpy(h264->sprop_level_parameter_sets, p1+1, vc); h264->sprop_level_parameter_sets[vc] = '\0'; } else if(0 == strncasecmp("sprop-deint-buf-req", p, nc)) { h264->flags |= SDP_A_FMTP_H264_SPROP_DEINT_BUF_REQ; h264->sprop_deint_buf_req = (unsigned int)atoi(p1+1); } else if(0 == strncasecmp("sprop-interleaving-depth", p, nc)) { h264->flags |= SDP_A_FMTP_H264_SPROP_INTERLEAVING_DEPTH; h264->sprop_interleaving_depth = atoi(p1+1); } else if(0 == strncasecmp("sprop-max-don-diff", p, nc)) { h264->flags |= SDP_A_FMTP_H264_SPROP_MAX_DON_DIFF; h264->sprop_max_don_diff = (unsigned int)atoi(p1+1); } else if(0 == strncasecmp("sprop-init-buf-time", p, nc)) { if(vc >= sizeof(h264->sprop_init_buf_time)) return -1; h264->flags |= SDP_A_FMTP_H264_SPROP_INIT_BUF_TIME; memcpy(h264->sprop_init_buf_time, p1+1, vc); h264->sprop_init_buf_time[vc] = '\0'; } else if(0 == strncasecmp("sar-understood", p, nc)) { h264->flags |= SDP_A_FMTP_H264_SAR_UNDERSTOOD; h264->sar_understood = atoi(p1+1); } else if(0 == strncasecmp("sar-supported", p, nc)) { h264->flags |= SDP_A_FMTP_H264_SAR_SUPPORTED; h264->sar_supported = atoi(p1+1); } break; case 'r': // redundant-pic-cap if(0 == strncasecmp("redundant-pic-cap", p, nc)) { h264->flags |= SDP_A_FMTP_H264_REDUNDANT_PIC_CAP; h264->redundant_pic_cap = atoi(p1+1); } break; case 'd': // deint-buf-cap if(0 == strncasecmp("deint-buf-cap", p, nc)) { h264->flags |= SDP_A_FMTP_H264_DEINT_BUF_CAP; h264->deint_buf_cap = (unsigned int)atoi(p1+1); } break; case 'i': // in-band-parameter-sets if(0 == strncasecmp("in-band-parameter-sets", p, nc)) { h264->flags |= SDP_A_FMTP_H264_IN_BAND_PARAMETER_SETS; h264->in_band_parameter_sets = atoi(p1+1); } break; case 'u': // use-level-src-parameter-sets if(0 == strncasecmp("use-level-src-parameter-sets", p, nc)) { h264->flags |= SDP_A_FMTP_H264_USE_LEVEL_SRC_PARAMETER_SETS; h264->use_level_src_parameter_sets = atoi(p1+1); } break; case 'l': // level-asymmetry-allowed if(0 == strncasecmp("level-asymmetry-allowed", p, nc)) { h264->flags |= SDP_A_FMTP_H264_LEVEL_ASYMMETRY_ALLOWED; h264->level_asymmetry_allowed = atoi(p1+1); } break; } p = *p2 ? p2 + 1 : p2; } return 0; } // RFC7798 RTP Payload Format for High Efficiency Video Coding (HEVC) // m=video 49170 RTP/AVP 98 // a=rtpmap:98 H265/90000 // a=fmtp:98 profile-id=1; sprop-vps=