void
SipccSdpAttributeList::LoadFmtp(sdp_t* sdp, uint16_t level)
{
  auto fmtps = MakeUnique<SdpFmtpAttributeList>();

  for (uint16_t i = 1; i < UINT16_MAX; ++i) {
    sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_FMTP, i);

    if (!attr) {
      break;
    }

    sdp_fmtp_t* fmtp = &(attr->attr.fmtp);

    // Get the payload type
    std::stringstream osPayloadType;
    // payload_num is the number in the fmtp attribute, verbatim
    osPayloadType << fmtp->payload_num;

    // Get parsed form of parameters, if supported
    UniquePtr<SdpFmtpAttributeList::Parameters> parameters;

    rtp_ptype codec = sdp_get_known_payload_type(sdp, level, fmtp->payload_num);

    switch (codec) {
      case RTP_H264_P0:
      case RTP_H264_P1: {
        SdpFmtpAttributeList::H264Parameters* h264Parameters(
            new SdpFmtpAttributeList::H264Parameters);

        sstrncpy(h264Parameters->sprop_parameter_sets, fmtp->parameter_sets,
                 sizeof(h264Parameters->sprop_parameter_sets));

        h264Parameters->level_asymmetry_allowed =
            !!(fmtp->level_asymmetry_allowed);

        h264Parameters->packetization_mode = fmtp->packetization_mode;
        sscanf(fmtp->profile_level_id, "%x", &h264Parameters->profile_level_id);
        h264Parameters->max_mbps = fmtp->max_mbps;
        h264Parameters->max_fs = fmtp->max_fs;
        h264Parameters->max_cpb = fmtp->max_cpb;
        h264Parameters->max_dpb = fmtp->max_dpb;
        h264Parameters->max_br = fmtp->max_br;

        parameters.reset(h264Parameters);
      } break;
      case RTP_VP9: {
        SdpFmtpAttributeList::VP8Parameters* vp9Parameters(
            new SdpFmtpAttributeList::VP8Parameters(
              SdpRtpmapAttributeList::kVP9));

        vp9Parameters->max_fs = fmtp->max_fs;
        vp9Parameters->max_fr = fmtp->max_fr;

        parameters.reset(vp9Parameters);
      } break;
      case RTP_VP8: {
        SdpFmtpAttributeList::VP8Parameters* vp8Parameters(
            new SdpFmtpAttributeList::VP8Parameters(
              SdpRtpmapAttributeList::kVP8));

        vp8Parameters->max_fs = fmtp->max_fs;
        vp8Parameters->max_fr = fmtp->max_fr;

        parameters.reset(vp8Parameters);
      } break;
      case RTP_RED: {
        SdpFmtpAttributeList::RedParameters* redParameters(
            new SdpFmtpAttributeList::RedParameters);
        for (int i = 0;
             i < SDP_FMTP_MAX_REDUNDANT_ENCODINGS && fmtp->redundant_encodings[i];
             ++i) {
          redParameters->encodings.push_back(fmtp->redundant_encodings[i]);
        }

        parameters.reset(redParameters);
      } break;
      case RTP_OPUS: {
        SdpFmtpAttributeList::OpusParameters* opusParameters(
            new SdpFmtpAttributeList::OpusParameters);
        opusParameters->maxplaybackrate = fmtp->maxplaybackrate;
        opusParameters->stereo = fmtp->stereo;
        opusParameters->useInBandFec = fmtp->useinbandfec;
        parameters.reset(opusParameters);
      } break;
      default: {
      }
    }

    fmtps->PushEntry(osPayloadType.str(), Move(parameters));
  }

  if (!fmtps->mFmtps.empty()) {
    SetAttribute(fmtps.release());
  }
}
void
SipccSdpAttributeList::LoadFmtp(sdp_t* sdp, uint16_t level)
{
  auto fmtps = MakeUnique<SdpFmtpAttributeList>();

  for (uint16_t i = 1; i < UINT16_MAX; ++i) {
    sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_FMTP, i);

    if (!attr) {
      break;
    }

    sdp_fmtp_t* fmtp = &(attr->attr.fmtp);

    // Get the payload type
    std::stringstream osPayloadType;
    // payload_num is the number in the fmtp attribute, verbatim
    osPayloadType << fmtp->payload_num;

    // Get the serialized form of the parameters
    flex_string fs;
    flex_string_init(&fs);

    // Very lame, but we need direct access so we can get the serialized form
    sdp_result_e sdpres = sdp_build_attr_fmtp_params(sdp, fmtp, &fs);

    if (sdpres != SDP_SUCCESS) {
      flex_string_free(&fs);
      continue;
    }

    std::string paramsString(fs.buffer);
    flex_string_free(&fs);

    // Get parsed form of parameters, if supported
    UniquePtr<SdpFmtpAttributeList::Parameters> parameters;

    rtp_ptype codec = sdp_get_known_payload_type(sdp, level, fmtp->payload_num);

    switch (codec) {
      case RTP_H264_P0:
      case RTP_H264_P1: {
        SdpFmtpAttributeList::H264Parameters* h264Parameters(
            new SdpFmtpAttributeList::H264Parameters);

        sstrncpy(h264Parameters->sprop_parameter_sets, fmtp->parameter_sets,
                 sizeof(h264Parameters->sprop_parameter_sets));

        h264Parameters->level_asymmetry_allowed =
            !!(fmtp->level_asymmetry_allowed);

        h264Parameters->packetization_mode = fmtp->packetization_mode;
// Copied from VcmSIPCCBinding
#ifdef _WIN32
        sscanf_s(fmtp->profile_level_id, "%x",
                 &h264Parameters->profile_level_id, sizeof(unsigned*));
#else
        sscanf(fmtp->profile_level_id, "%xu",
               &h264Parameters->profile_level_id);
#endif
        h264Parameters->max_mbps = fmtp->max_mbps;
        h264Parameters->max_fs = fmtp->max_fs;
        h264Parameters->max_cpb = fmtp->max_cpb;
        h264Parameters->max_dpb = fmtp->max_dpb;
        h264Parameters->max_br = fmtp->max_br;

        parameters.reset(h264Parameters);
      } break;
      case RTP_VP9: {
        SdpFmtpAttributeList::VP8Parameters* vp9Parameters(
            new SdpFmtpAttributeList::VP8Parameters(
              SdpRtpmapAttributeList::kVP9));

        vp9Parameters->max_fs = fmtp->max_fs;
        vp9Parameters->max_fr = fmtp->max_fr;

        parameters.reset(vp9Parameters);
      } break;
      case RTP_VP8: {
        SdpFmtpAttributeList::VP8Parameters* vp8Parameters(
            new SdpFmtpAttributeList::VP8Parameters(
              SdpRtpmapAttributeList::kVP8));

        vp8Parameters->max_fs = fmtp->max_fs;
        vp8Parameters->max_fr = fmtp->max_fr;

        parameters.reset(vp8Parameters);
      } break;
      default: {
      }
    }

    fmtps->PushEntry(osPayloadType.str(), paramsString, Move(parameters));
  }

  if (!fmtps->mFmtps.empty()) {
    SetAttribute(fmtps.release());
  }
}