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
This commit is contained in:
Johannes Willbold 2018-06-29 14:42:19 -07:00
parent 02f6b7fef7
commit c34d1a7a92
2 changed files with 436 additions and 12 deletions

View File

@ -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<u32>), // min, max, step
DiscrateValues(Vec<u32>),
Value(u32)
}
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature="serialize", derive(Serialize))]
pub enum SdpAttributeImageAttrSRange {
Range(f32,f32), // min, max
DiscrateValues(Vec<f32>),
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<SdpAttributeImageAttrSRange>,
pub par: Option<SdpAttributeImageAttrPRange>,
pub q: Option<f32>,
}
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature="serialize", derive(Serialize))]
pub enum SdpAttributeImageAttrSetList {
Sets(Vec<SdpAttributeImageAttrSet>),
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<SdpAttribute, SdpParserInternalEr
Ok(SdpAttribute::IceOptions(to_parse.split_whitespace().map(|x| x.to_string()).collect()))
}
fn parse_image_attr_xyrange(to_parse: &str) -> Result<SdpAttributeImageAttrXYRange, SdpParserInternalError> {
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::<u32>()?,
range_tokens[2].parse::<u32>()?,
Some(range_tokens[1].parse::<u32>()?),
))
} else if range_tokens.len() == 2 {
Ok(SdpAttributeImageAttrXYRange::Range(
range_tokens[0].parse::<u32>()?,
range_tokens[1].parse::<u32>()?,
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::<u32>())
.collect::<Result<Vec<u32>, _>>()?;
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::<u32>()?))
}
}
fn parse_image_attr_set(to_parse: &str) -> Result<SdpAttributeImageAttrSet, SdpParserInternalError> {
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<f32, SdpParserInternalError> {
match maybe_next {
Some(x) => Ok(x.parse::<f32>()?),
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 = &current_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::<f32>())
.collect::<Result<Vec<f32>, _>>()?;
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::<f32>()?))
}
} else if current_token.starts_with("par=") {
let braced_value_token = &current_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::<f32>()?);
} 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<SdpAttribute, SdpParserInternalError> {
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<SdpAttributeImageAttrSet, SdpParserInternalError> {
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<SdpAttribute, SdpParserInternalError> {
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]

View File

@ -744,19 +744,38 @@ pub unsafe extern "C" fn sdp_get_rtcpfbs(attributes: *const Vec<SdpAttribute>, 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<SdpAttribute>) -> size_t {
count_attribute((*attributes).as_slice(), RustSdpAttributeType::ImageAttr)
}
#[no_mangle]
pub unsafe extern "C" fn sdp_get_imageattrs(attributes: *const Vec<SdpAttribute>, 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<SdpAttribute>, 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());
}