From c34d1a7a929f79db4d6f3adb54016fa232f4aa14 Mon Sep 17 00:00:00 2001 From: Johannes Willbold Date: Fri, 29 Jun 2018 14:42:19 -0700 Subject: [PATCH] Bug 1432930: Part 1: Added imageattr parsing in rust, r=bwc Added imageattr parsing in rust. Expanded the imageattr test cases in rust. MozReview-Commit-ID: IeMkbrbJAoe --HG-- extra : rebase_source : 05e4105983e7d735bce21de3bd4e99da754589ed --- .../src/sdp/rsdparsa/src/attribute_type.rs | 421 +++++++++++++++++- .../src/sdp/rsdparsa_capi/src/attribute.rs | 27 +- 2 files changed, 436 insertions(+), 12 deletions(-) diff --git a/media/webrtc/signaling/src/sdp/rsdparsa/src/attribute_type.rs b/media/webrtc/signaling/src/sdp/rsdparsa/src/attribute_type.rs index da1ad3f09636..bb69b769c154 100644 --- a/media/webrtc/signaling/src/sdp/rsdparsa/src/attribute_type.rs +++ b/media/webrtc/signaling/src/sdp/rsdparsa/src/attribute_type.rs @@ -14,7 +14,7 @@ pub enum SdpSingleDirection{ Recv = 2, } -#[derive(Clone)] +#[derive(Debug, PartialEq, Clone)] #[cfg_attr(feature="serialize", derive(Serialize))] pub enum SdpAttributePayloadType { PayloadType(u8), @@ -289,6 +289,54 @@ pub struct SdpAttributeFingerprint { pub fingerprint: String, } +#[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature="serialize", derive(Serialize))] +pub enum SdpAttributeImageAttrXYRange { + Range(u32,u32,Option), // min, max, step + DiscrateValues(Vec), + Value(u32) +} + +#[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature="serialize", derive(Serialize))] +pub enum SdpAttributeImageAttrSRange { + Range(f32,f32), // min, max + DiscrateValues(Vec), + Value(f32) +} + +#[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature="serialize", derive(Serialize))] +pub struct SdpAttributeImageAttrPRange { + pub min: f32, + pub max: f32, +} + +#[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature="serialize", derive(Serialize))] +pub struct SdpAttributeImageAttrSet { + pub x: SdpAttributeImageAttrXYRange, + pub y: SdpAttributeImageAttrXYRange, + pub sar: Option, + pub par: Option, + pub q: Option, +} + +#[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature="serialize", derive(Serialize))] +pub enum SdpAttributeImageAttrSetList { + Sets(Vec), + Wildcard, +} + +#[derive(Clone)] +#[cfg_attr(feature="serialize", derive(Serialize))] +pub struct SdpAttributeImageAttr { + pub pt: SdpAttributePayloadType, + pub send: SdpAttributeImageAttrSetList, + pub recv: SdpAttributeImageAttrSetList, +} + #[derive(Clone)] #[cfg_attr(feature="serialize", derive(Serialize))] pub struct SdpAttributeSctpmap { @@ -430,7 +478,7 @@ pub enum SdpAttribute { IcePwd(String), IceUfrag(String), Identity(String), - ImageAttr(String), + ImageAttr(SdpAttributeImageAttr), Inactive, Label(String), MaxMessageSize(u64), @@ -632,7 +680,7 @@ impl FromStr for SdpAttribute { "ice-pwd" => Ok(SdpAttribute::IcePwd(string_or_empty(val)?)), "ice-ufrag" => Ok(SdpAttribute::IceUfrag(string_or_empty(val)?)), "identity" => Ok(SdpAttribute::Identity(string_or_empty(val)?)), - "imageattr" => Ok(SdpAttribute::ImageAttr(string_or_empty(val)?)), + "imageattr" => parse_image_attr(val), "inactive" => Ok(SdpAttribute::Inactive), "label" => Ok(SdpAttribute::Label(string_or_empty(val)?)), "max-message-size" => Ok(SdpAttribute::MaxMessageSize(val.parse()?)), @@ -1174,6 +1222,295 @@ fn parse_ice_options(to_parse: &str) -> Result Result { + if to_parse.starts_with("[") { + if !to_parse.ends_with("]") { + return Err(SdpParserInternalError::Generic( + "imageattr's xyrange has no closing tag ']'".to_string() + )) + } + + if to_parse.contains(":") { + // Range values + let range_tokens:Vec<&str> = to_parse[1..to_parse.len()-1].split(":").collect(); + + if range_tokens.len() == 3 { + Ok(SdpAttributeImageAttrXYRange::Range( + range_tokens[0].parse::()?, + range_tokens[2].parse::()?, + Some(range_tokens[1].parse::()?), + )) + } else if range_tokens.len() == 2 { + Ok(SdpAttributeImageAttrXYRange::Range( + range_tokens[0].parse::()?, + range_tokens[1].parse::()?, + None + )) + } else { + return Err(SdpParserInternalError::Generic( + "imageattr's xyrange must contain 2 or 3 fields".to_string() + )) + } + } else { + // Discrete values + let values = to_parse[1..to_parse.len()-1] + .split(",") + .map(|x| x.parse::()) + .collect::, _>>()?; + + if values.len() == 0 { + return Err(SdpParserInternalError::Generic( + "imageattr's discrete value list is empty".to_string() + )) + } + + Ok(SdpAttributeImageAttrXYRange::DiscrateValues(values)) + } + + } else { + Ok(SdpAttributeImageAttrXYRange::Value(to_parse.parse::()?)) + } +} + +fn parse_image_attr_set(to_parse: &str) -> Result { + let result_from_option = |opt, error_msg: &str| { + match opt { + Some(x) => Ok(x), + None => Err(SdpParserInternalError::Generic(error_msg.to_string())) + } + }; + + let mut tokens = Vec::new(); + let mut currently_in_braces = false; + let mut current_tokens = Vec::new(); + + for token in to_parse.split(",") { + if token.contains("[") { + currently_in_braces = true; + } + if token.contains("]") { + currently_in_braces = false; + } + + current_tokens.push(token.to_string()); + + if !currently_in_braces { + tokens.push(current_tokens.join(",")); + current_tokens = Vec::new(); + } + } + + + let mut tokens = tokens.into_iter(); + + let x_token = result_from_option(tokens.next(),"imageattr set is missing the 'x=' token")?; + if !x_token.starts_with("x=") { + return Err(SdpParserInternalError::Generic( + "The first token in an imageattr set must begin with 'x='".to_string() + )) + } + let x = parse_image_attr_xyrange(&x_token[2..])?; + + + let y_token = result_from_option(tokens.next(),"imageattr set is missing the 'y=' token")?; + if !y_token.starts_with("y=") { + return Err(SdpParserInternalError::Generic( + "The second token in an imageattr set must begin with 'y='".to_string() + )) + } + let y = parse_image_attr_xyrange(&y_token[2..])?; + + let mut sar = None; + let mut par = None; + let mut q = None; + + let parse_ps_range = |x: &str| -> Result<(f32, f32), SdpParserInternalError> { + let range_tokens = &x[1..x.len()-1]; + + let parse_prange_value = |maybe_next: Option<&str>| -> Result { + match maybe_next { + Some(x) => Ok(x.parse::()?), + None => Err(SdpParserInternalError::Generic( + "imageattr's par and sar ranges must have two components" + .to_string())) + } + }; + + let mut minmax_pair = range_tokens.split("-"); + + let min = parse_prange_value(minmax_pair.next())?; + let max = parse_prange_value(minmax_pair.next())?; + + if min >= max { + return Err(SdpParserInternalError::Generic( + "In imageattr's par and sar ranges, first must be < than the second".to_string() + )) + } + + Ok((min,max)) + }; + + while let Some(current_token) = tokens.next() { + if current_token.starts_with("sar=") { + let value_token = ¤t_token[4..]; + if value_token.starts_with("[") { + if !value_token.ends_with("]") { + return Err(SdpParserInternalError::Generic( + "imageattr's sar value is missing closing tag ']'".to_string() + )) + } + + if value_token.contains("-") { + // Range + let range = parse_ps_range(&value_token)?; + sar = Some(SdpAttributeImageAttrSRange::Range(range.0,range.1)) + } else if value_token.contains(",") { + // Discrete values + let values = value_token[1..value_token.len()-1] + .split(",") + .map(|x| x.parse::()) + .collect::, _>>()?; + + if values.len() == 0 { + return Err(SdpParserInternalError::Generic( + "imageattr's sar discrete value list is empty".to_string() + )) + } + + // Check that all the values are ascending + let mut last_value = 0.0; + for value in &values { + if last_value >= *value { + return Err(SdpParserInternalError::Generic( + "imageattr's sar discrete value list must contain ascending values" + .to_string() + )) + } + last_value = *value; + } + sar = Some(SdpAttributeImageAttrSRange::DiscrateValues(values)) + } + } else { + sar = Some(SdpAttributeImageAttrSRange::Value(value_token.parse::()?)) + } + } else if current_token.starts_with("par=") { + let braced_value_token = ¤t_token[4..]; + if !braced_value_token.starts_with("[") || !braced_value_token.ends_with("]") { + return Err(SdpParserInternalError::Generic( + "imageattr's par value is missing braces".to_string() + )) + } + + let range = parse_ps_range(&braced_value_token)?; + par = Some(SdpAttributeImageAttrPRange { + min: range.0, + max: range.1, + }) + } else if current_token.starts_with("q=") { + q = Some(current_token[2..].parse::()?); + } else { + return Err(SdpParserInternalError::Generic( + format!("imageattr set contains unknown value token '{:?}'", current_token) + .to_string() + )) + } + } + + Ok(SdpAttributeImageAttrSet { + x, + y, + sar, + par, + q + }) +} + +fn parse_image_attr(to_parse: &str) -> Result { + let result_from_option = |opt, error_msg: &str| { + match opt { + Some(x) => Ok(x), + None => Err(SdpParserInternalError::Generic(error_msg.to_string())) + } + }; + let mut tokens = to_parse.split(' ').peekable(); + + let pt = parse_payload_type(result_from_option(tokens.next(), + "imageattr's requires a payload token")?)?; + let first_direction = parse_single_direction(result_from_option(tokens.next(), "")?)?; + + let parse_set = |set_token:&str| -> Result { + Ok(parse_image_attr_set(&set_token[1..set_token.len()-1])?) + }; + + let first_set_list = match result_from_option(tokens.next(), + "imageattr must have at least one parameter set")? { + "*" => SdpAttributeImageAttrSetList::Wildcard, + x @ _ => { + let mut sets = vec![parse_set(x)?]; + while let Some(set_str) = tokens.clone().peek() { + if set_str.starts_with("[") && set_str.ends_with("]") { + sets.push(parse_set(tokens.next().unwrap())?); + } else { + break; + } + } + + SdpAttributeImageAttrSetList::Sets(sets) + } + }; + + let mut second_set_list = SdpAttributeImageAttrSetList::Sets(Vec::new()); + + // Check if there is a second direction defined + if let Some(x) = tokens.next() { + if parse_single_direction(x)? == first_direction { + return Err(SdpParserInternalError::Generic( + "image-attr's second direction token must be different from the first one" + .to_string() + )) + } + + second_set_list = match result_from_option(tokens.next(), + "imageattr must have a parameter set after a direction token")? { + "*" => SdpAttributeImageAttrSetList::Wildcard, + x @ _ => { + let mut sets = vec![parse_set(x)?]; + while let Some(set_str) = tokens.clone().peek() { + if set_str.starts_with("[") && set_str.ends_with("]") { + sets.push(parse_set(tokens.next().unwrap())?); + } else { + break; + } + } + + SdpAttributeImageAttrSetList::Sets(sets) + } + }; + } + + + if let Some(_) = tokens.next() { + return Err(SdpParserInternalError::Generic( + "imageattr must not contain any token after the second set list".to_string() + )) + } + + Ok(SdpAttribute::ImageAttr(match first_direction { + SdpSingleDirection::Send => + SdpAttributeImageAttr { + pt, + send: first_set_list, + recv: second_set_list, + }, + SdpSingleDirection::Recv => + SdpAttributeImageAttr { + pt, + send: second_set_list, + recv: first_set_list, + } + })) +} + fn parse_msid(to_parse: &str) -> Result { let mut tokens = to_parse.split_whitespace(); let id = match tokens.next() { @@ -1884,16 +2221,84 @@ fn test_parse_attribute_identity() { #[test] fn test_parse_attribute_imageattr() { + let check_parse = |x| -> SdpAttributeImageAttr { + if let Ok(SdpType::Attribute(SdpAttribute::ImageAttr(x))) = parse_attribute(x) { + x + } else { + unreachable!(); + } + }; + assert!(parse_attribute("imageattr:120 send * recv *").is_ok()); - assert!( - parse_attribute( - "imageattr:97 send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] recv [x=330,y=250]" - ).is_ok() - ); + assert!(parse_attribute("imageattr:99 send [x=320,y=240] recv [x=320,y=240]").is_ok()); + assert!(parse_attribute("imageattr:97 send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] recv [x=330,y=250]").is_ok()); assert!(parse_attribute("imageattr:97 recv [x=800,y=640,sar=1.1] send [x=330,y=250]").is_ok()); assert!(parse_attribute("imageattr:97 send [x=[480:16:800],y=[320:16:640],par=[1.2-1.3],q=0.6] [x=[176:8:208],y=[144:8:176],par=[1.2-1.3]] recv *").is_ok()); + let mut imageattr = check_parse("imageattr:* recv [x=800,y=[50,80,30],sar=1.1] send [x=330,y=250,sar=[1.1,1.3,1.9],q=0.1]"); + assert_eq!(imageattr.pt, SdpAttributePayloadType::Wildcard); + match imageattr.recv { + SdpAttributeImageAttrSetList::Sets(sets) => { + assert_eq!(sets.len(), 1); + + let set = &sets[0]; + assert_eq!(set.x, SdpAttributeImageAttrXYRange::Value(800)); + assert_eq!(set.y, SdpAttributeImageAttrXYRange::DiscrateValues(vec![50,80,30])); + assert_eq!(set.par, None); + assert_eq!(set.sar, Some(SdpAttributeImageAttrSRange::Value(1.1))); + assert_eq!(set.q, None); + + }, + _ => { unreachable!(); } + } + match imageattr.send { + SdpAttributeImageAttrSetList::Sets(sets) => { + assert_eq!(sets.len(), 1); + + let set = &sets[0]; + assert_eq!(set.x, SdpAttributeImageAttrXYRange::Value(330)); + assert_eq!(set.y, SdpAttributeImageAttrXYRange::Value(250)); + assert_eq!(set.par, None); + assert_eq!(set.sar, Some(SdpAttributeImageAttrSRange::DiscrateValues(vec![1.1,1.3,1.9]))); + assert_eq!(set.q, Some(0.1)); + }, + _ => { unreachable!(); } + } + + imageattr = check_parse("imageattr:97 send [x=[480:16:800],y=[100,200,300],par=[1.2-1.3],q=0.6] [x=1080,y=[144:176],sar=[0.5-0.7]] recv *"); + assert_eq!(imageattr.pt, SdpAttributePayloadType::PayloadType(97)); + match imageattr.send { + SdpAttributeImageAttrSetList::Sets(sets) => { + assert_eq!(sets.len(), 2); + + let first_set = &sets[0]; + assert_eq!(first_set.x, SdpAttributeImageAttrXYRange::Range(480, 800, Some(16))); + assert_eq!(first_set.y, SdpAttributeImageAttrXYRange::DiscrateValues(vec![100, 200, 300])); + assert_eq!(first_set.par, Some(SdpAttributeImageAttrPRange { + min: 1.2, + max: 1.3 + })); + assert_eq!(first_set.sar, None); + assert_eq!(first_set.q, Some(0.6)); + + let second_set = &sets[1]; + assert_eq!(second_set.x, SdpAttributeImageAttrXYRange::Value(1080)); + assert_eq!(second_set.y, SdpAttributeImageAttrXYRange::Range(144, 176, None)); + assert_eq!(second_set.par, None); + assert_eq!(second_set.sar, Some(SdpAttributeImageAttrSRange::Range(0.5, 0.7))); + assert_eq!(second_set.q, None); + }, + _ => { unreachable!(); } + } + assert_eq!(imageattr.recv, SdpAttributeImageAttrSetList::Wildcard); + + assert!(parse_attribute("imageattr:99 send [x=320,y=240]").is_ok()); + assert!(parse_attribute("imageattr:100 recv [x=320,y=240]").is_ok()); + assert!(parse_attribute("imageattr:").is_err()); + assert!(parse_attribute("imageattr:100").is_err()); + assert!(parse_attribute("imageattr:120 send * recv * send *").is_err()); + assert!(parse_attribute("imageattr:97 send [x=800,y=640,sar=1.1] send [x=330,y=250]").is_err()); } #[test] diff --git a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/attribute.rs b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/attribute.rs index 10a51ac4cf53..53aa6c4d2fbf 100644 --- a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/attribute.rs +++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/attribute.rs @@ -744,19 +744,38 @@ pub unsafe extern "C" fn sdp_get_rtcpfbs(attributes: *const Vec, r } + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct RustSdpAttributeImageAttr { + pub pt: u32, +} + +impl<'a> From<&'a SdpAttributeImageAttr> for RustSdpAttributeImageAttr { + fn from(other: &SdpAttributeImageAttr) -> Self { + RustSdpAttributeImageAttr { + pt: match other.pt { + SdpAttributePayloadType::Wildcard => u32::max_value(), + SdpAttributePayloadType::PayloadType(x) => x as u32, + }, + } + } +} + + #[no_mangle] pub unsafe extern "C" fn sdp_get_imageattr_count(attributes: *const Vec) -> size_t { count_attribute((*attributes).as_slice(), RustSdpAttributeType::ImageAttr) } #[no_mangle] -pub unsafe extern "C" fn sdp_get_imageattrs(attributes: *const Vec, ret_size: size_t, ret_groups: *mut StringView) { - let attrs: Vec<_> = (*attributes).iter().filter_map(|x| if let SdpAttribute::ImageAttr(ref string) = *x { - Some(StringView::from(string.as_str())) +pub unsafe extern "C" fn sdp_get_imageattrs(attributes: *const Vec, ret_size: size_t, ret_attrs: *mut RustSdpAttributeImageAttr) { + let attrs: Vec<_> = (*attributes).iter().filter_map(|x| if let SdpAttribute::ImageAttr(ref data) = *x { + Some(RustSdpAttributeImageAttr::from(data)) } else { None }).collect(); - let imageattrs = slice::from_raw_parts_mut(ret_groups, ret_size); + let imageattrs = slice::from_raw_parts_mut(ret_attrs, ret_size); imageattrs.copy_from_slice(attrs.as_slice()); }