/rust/registry/src/index.crates.io-6f17d22bba15001f/av1-grain-0.2.4/src/parse.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2022-2022, The rav1e contributors. All rights reserved |
2 | | // |
3 | | // This source code is subject to the terms of the BSD 2 Clause License and |
4 | | // the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License |
5 | | // was not distributed with this source code in the LICENSE file, you can |
6 | | // obtain it at www.aomedia.org/license/software. If the Alliance for Open |
7 | | // Media Patent License 1.0 was not distributed with this source code in the |
8 | | // PATENTS file, you can obtain it at www.aomedia.org/license/patent. |
9 | | |
10 | | use std::ops::{Range, RangeFrom, RangeTo}; |
11 | | |
12 | | use arrayvec::ArrayVec; |
13 | | use nom::{ |
14 | | branch::alt, |
15 | | bytes::complete::tag, |
16 | | character::complete::{char, digit1, line_ending, multispace0, multispace1, space0, space1}, |
17 | | combinator::{eof, map_res, opt, recognize}, |
18 | | error::{Error as NomError, ErrorKind, FromExternalError, ParseError}, |
19 | | multi::{many1, separated_list0, separated_list1}, |
20 | | sequence::{delimited, preceded}, |
21 | | AsChar, Compare, Err as NomErr, IResult, InputIter, InputLength, InputTakeAtPosition, Parser, |
22 | | Slice, |
23 | | }; |
24 | | |
25 | | use crate::{GrainTableSegment, NUM_UV_COEFFS, NUM_UV_POINTS, NUM_Y_COEFFS, NUM_Y_POINTS}; |
26 | | |
27 | | /// This file has the implementation details of the grain table. |
28 | | /// |
29 | | /// The file format is an ascii representation for readability and |
30 | | /// editability. Array parameters are separated from the non-array |
31 | | /// parameters and prefixed with a few characters to make for easy |
32 | | /// localization with a parameter set. Each entry is prefixed with "E" |
33 | | /// and the other parameters are only specified if "apply-grain" is |
34 | | /// non-zero. |
35 | | /// |
36 | | /// ```text |
37 | | /// filmgrn1 |
38 | | /// E <start-time> <end-time> <apply-grain> <random-seed> <dynamic-grain> |
39 | | /// p <ar_coeff_lag> <ar_coeff_shift> <grain_scale_shift> ... |
40 | | /// sY <num_y_points> <point_0_x> <point_0_y> ... |
41 | | /// sCb <num_cb_points> <point_0_x> <point_0_y> ... |
42 | | /// sCr <num_cr_points> <point_0_x> <point_0_y> ... |
43 | | /// cY <ar_coeff_y_0> .... |
44 | | /// cCb <ar_coeff_cb_0> .... |
45 | | /// cCr <ar_coeff_cr_0> .... |
46 | | /// E <start-time> ... |
47 | | /// ``` |
48 | | /// |
49 | | /// # Errors |
50 | | /// |
51 | | /// - If the file cannot be opened |
52 | | /// - If the file does not contain a properly formatted film grain table |
53 | 0 | pub fn parse_grain_table(input: &str) -> anyhow::Result<Vec<GrainTableSegment>> { |
54 | 0 | let (input, _) = grain_table_header(input).map_err(|e| anyhow::anyhow!(e.to_string()))?; |
55 | 0 | let (_, segments) = |
56 | 0 | many1(grain_table_segment)(input).map_err(|e| anyhow::anyhow!(e.to_string()))?; |
57 | 0 | Ok(segments.into_iter().flatten().collect()) |
58 | 0 | } |
59 | | |
60 | 0 | fn grain_table_header(input: &str) -> IResult<&str, ()> { |
61 | 0 | let (input, _) = delimited(multispace0, tag("filmgrn1"), line_ending)(input)?; |
62 | 0 | Ok((input, ())) |
63 | 0 | } |
64 | | |
65 | | // FIXME: Clippy false positive |
66 | | #[allow(clippy::trait_duplication_in_bounds)] |
67 | 0 | fn line<I, O, E: ParseError<I>, F>(parser: F) -> impl FnMut(I) -> IResult<I, O, E> |
68 | 0 | where |
69 | 0 | I: InputTakeAtPosition |
70 | 0 | + Clone |
71 | 0 | + Slice<Range<usize>> |
72 | 0 | + Slice<RangeFrom<usize>> |
73 | 0 | + Slice<RangeTo<usize>> |
74 | 0 | + InputIter |
75 | 0 | + InputLength |
76 | 0 | + Compare<&'static str>, |
77 | 0 | <I as InputTakeAtPosition>::Item: AsChar + Clone, |
78 | 0 | F: Parser<I, O, E>, |
79 | 0 | { |
80 | 0 | delimited(multispace0, parser, alt((line_ending, eof))) |
81 | 0 | } Unexecuted instantiation: av1_grain::parse::line::<&str, alloc::vec::Vec<&str>, nom::error::Error<&str>, nom::sequence::preceded<&str, &str, alloc::vec::Vec<&str>, nom::error::Error<&str>, nom::bytes::complete::tag<&str, &str, nom::error::Error<&str>>::{closure#0}, nom::sequence::preceded<&str, &str, alloc::vec::Vec<&str>, nom::error::Error<&str>, nom::character::complete::space0<&str, nom::error::Error<&str>>, nom::multi::separated_list0<&str, &str, &str, nom::error::Error<&str>, av1_grain::parse::integer, nom::character::complete::multispace1<&str, nom::error::Error<&str>>>::{closure#0}>::{closure#0}>::{closure#0}> Unexecuted instantiation: av1_grain::parse::line::<&str, alloc::vec::Vec<&str>, nom::error::Error<&str>, nom::sequence::preceded<&str, &str, alloc::vec::Vec<&str>, nom::error::Error<&str>, nom::bytes::complete::tag<&str, &str, nom::error::Error<&str>>::{closure#0}, nom::sequence::preceded<&str, &str, alloc::vec::Vec<&str>, nom::error::Error<&str>, nom::character::complete::space1<&str, nom::error::Error<&str>>, nom::multi::separated_list1<&str, &str, &str, nom::error::Error<&str>, nom::character::complete::digit1<&str, nom::error::Error<&str>>, nom::character::complete::space1<&str, nom::error::Error<&str>>>::{closure#0}>::{closure#0}>::{closure#0}> Unexecuted instantiation: av1_grain::parse::line::<&str, alloc::vec::Vec<&str>, nom::error::Error<&str>, nom::sequence::preceded<&str, &str, alloc::vec::Vec<&str>, nom::error::Error<&str>, nom::bytes::complete::tag<&str, &str, nom::error::Error<&str>>::{closure#0}, nom::sequence::preceded<&str, &str, alloc::vec::Vec<&str>, nom::error::Error<&str>, nom::character::complete::space1<&str, nom::error::Error<&str>>, nom::multi::separated_list1<&str, &str, &str, nom::error::Error<&str>, av1_grain::parse::integer, nom::character::complete::multispace1<&str, nom::error::Error<&str>>>::{closure#0}>::{closure#0}>::{closure#0}> |
82 | | |
83 | 0 | fn grain_table_segment(input: &str) -> IResult<&str, Option<GrainTableSegment>> { |
84 | 0 | let (input, e_params) = e_params(input)?; |
85 | 0 | if !e_params.apply { |
86 | | // I'm not sure *why* there's even an option to generate a film grain config |
87 | | // that doesn't apply film grain. But, well, I didn't make this format. |
88 | 0 | return Ok((input, None)); |
89 | 0 | } |
90 | | |
91 | 0 | let (input, p_params) = p_params(input)?; |
92 | 0 | let (input, s_y_params) = s_y_params(input)?; |
93 | 0 | let (input, s_cb_params) = s_cb_params(input)?; |
94 | 0 | let (input, s_cr_params) = s_cr_params(input)?; |
95 | 0 | let coeff_count = (2 * p_params.ar_coeff_lag * (p_params.ar_coeff_lag + 1)) as usize; |
96 | 0 | let (input, c_y_params) = c_y_params(input, coeff_count)?; |
97 | 0 | let (input, c_cb_params) = c_cb_params(input, coeff_count)?; |
98 | 0 | let (input, c_cr_params) = c_cr_params(input, coeff_count)?; |
99 | | |
100 | 0 | Ok(( |
101 | 0 | input, |
102 | 0 | Some(GrainTableSegment { |
103 | 0 | start_time: e_params.start, |
104 | 0 | end_time: e_params.end, |
105 | 0 | scaling_points_y: s_y_params, |
106 | 0 | scaling_points_cb: s_cb_params, |
107 | 0 | scaling_points_cr: s_cr_params, |
108 | 0 | scaling_shift: p_params.scaling_shift, |
109 | 0 | ar_coeff_lag: p_params.ar_coeff_lag, |
110 | 0 | ar_coeffs_y: c_y_params, |
111 | 0 | ar_coeffs_cb: c_cb_params, |
112 | 0 | ar_coeffs_cr: c_cr_params, |
113 | 0 | ar_coeff_shift: p_params.ar_coeff_shift, |
114 | 0 | cb_mult: p_params.cb_mult, |
115 | 0 | cb_luma_mult: p_params.cb_luma_mult, |
116 | 0 | cb_offset: p_params.cb_offset, |
117 | 0 | cr_mult: p_params.cr_mult, |
118 | 0 | cr_luma_mult: p_params.cr_luma_mult, |
119 | 0 | cr_offset: p_params.cr_offset, |
120 | 0 | overlap_flag: p_params.overlap_flag, |
121 | 0 | chroma_scaling_from_luma: p_params.chroma_scaling_from_luma, |
122 | 0 | grain_scale_shift: p_params.grain_scale_shift, |
123 | 0 | random_seed: e_params.seed, |
124 | 0 | }), |
125 | 0 | )) |
126 | 0 | } |
127 | | |
128 | | #[derive(Debug, Clone, Copy)] |
129 | | struct EParams { |
130 | | pub start: u64, |
131 | | pub end: u64, |
132 | | pub apply: bool, |
133 | | pub seed: u16, |
134 | | } |
135 | | |
136 | 0 | fn e_params(input: &str) -> IResult<&str, EParams> { |
137 | 0 | let (input, params) = map_res( |
138 | 0 | line(preceded( |
139 | 0 | tag("E"), |
140 | 0 | preceded(space1, separated_list1(space1, digit1)), |
141 | 0 | )), |
142 | 0 | |items: Vec<&str>| { |
143 | 0 | if items.len() != 5 { |
144 | 0 | return Err(NomErr::Failure(NomError::from_external_error( |
145 | 0 | input, |
146 | 0 | ErrorKind::Verify, |
147 | 0 | "Expected 5 values on E line", |
148 | 0 | ))); |
149 | 0 | } |
150 | 0 | let parsed = EParams { |
151 | 0 | start: items[0].parse().map_err(|_e| { |
152 | 0 | NomErr::Failure(NomError::from_external_error( |
153 | 0 | input, |
154 | 0 | ErrorKind::Digit, |
155 | 0 | "Failed to parse start_time", |
156 | 0 | )) |
157 | 0 | })?, |
158 | 0 | end: items[1].parse().map_err(|_e| { |
159 | 0 | NomErr::Failure(NomError::from_external_error( |
160 | 0 | input, |
161 | 0 | ErrorKind::Digit, |
162 | 0 | "Failed to parse end_time", |
163 | 0 | )) |
164 | 0 | })?, |
165 | 0 | apply: items[2].parse::<u8>().map_err(|_e| { |
166 | 0 | NomErr::Failure(NomError::from_external_error( |
167 | 0 | input, |
168 | 0 | ErrorKind::Digit, |
169 | 0 | "Failed to parse apply_grain", |
170 | 0 | )) |
171 | 0 | })? > 0, |
172 | 0 | seed: items[3].parse().map_err(|_e| { |
173 | 0 | NomErr::Failure(NomError::from_external_error( |
174 | 0 | input, |
175 | 0 | ErrorKind::Digit, |
176 | 0 | "Failed to parse random_seed", |
177 | 0 | )) |
178 | 0 | })?, |
179 | | }; |
180 | 0 | Ok(parsed) |
181 | 0 | }, |
182 | 0 | )(input)?; |
183 | | |
184 | 0 | if params.end < params.start { |
185 | 0 | return Err(NomErr::Failure(NomError::from_external_error( |
186 | 0 | input, |
187 | 0 | ErrorKind::Verify, |
188 | 0 | "Start time must be before end time", |
189 | 0 | ))); |
190 | 0 | } |
191 | 0 |
|
192 | 0 | Ok((input, params)) |
193 | 0 | } |
194 | | |
195 | | #[derive(Debug, Clone, Copy)] |
196 | | struct PParams { |
197 | | ar_coeff_lag: u8, |
198 | | ar_coeff_shift: u8, |
199 | | grain_scale_shift: u8, |
200 | | scaling_shift: u8, |
201 | | chroma_scaling_from_luma: bool, |
202 | | overlap_flag: bool, |
203 | | cb_mult: u8, |
204 | | cb_luma_mult: u8, |
205 | | cb_offset: u16, |
206 | | cr_mult: u8, |
207 | | cr_luma_mult: u8, |
208 | | cr_offset: u16, |
209 | | } |
210 | | |
211 | | #[allow(clippy::too_many_lines)] |
212 | 0 | fn p_params(input: &str) -> IResult<&str, PParams> { |
213 | 0 | let (input, params) = map_res( |
214 | 0 | line(preceded( |
215 | 0 | tag("p"), |
216 | 0 | preceded(space1, separated_list1(space1, digit1)), |
217 | 0 | )), |
218 | 0 | |items: Vec<&str>| { |
219 | 0 | if items.len() != 12 { |
220 | 0 | return Err(NomErr::Failure(NomError::from_external_error( |
221 | 0 | input, |
222 | 0 | ErrorKind::Verify, |
223 | 0 | "Expected 12 values on p line", |
224 | 0 | ))); |
225 | 0 | } |
226 | | |
227 | 0 | let parsed = PParams { |
228 | 0 | ar_coeff_lag: items[0].parse().map_err(|_e| { |
229 | 0 | NomErr::Failure(NomError::from_external_error( |
230 | 0 | input, |
231 | 0 | ErrorKind::Digit, |
232 | 0 | "Failed to parse ar_coeff_lag", |
233 | 0 | )) |
234 | 0 | })?, |
235 | 0 | ar_coeff_shift: items[1].parse().map_err(|_e| { |
236 | 0 | NomErr::Failure(NomError::from_external_error( |
237 | 0 | input, |
238 | 0 | ErrorKind::Digit, |
239 | 0 | "Failed to parse ar_coeff_shift", |
240 | 0 | )) |
241 | 0 | })?, |
242 | 0 | grain_scale_shift: items[2].parse().map_err(|_e| { |
243 | 0 | NomErr::Failure(NomError::from_external_error( |
244 | 0 | input, |
245 | 0 | ErrorKind::Digit, |
246 | 0 | "Failed to parse grain_scale_shift", |
247 | 0 | )) |
248 | 0 | })?, |
249 | 0 | scaling_shift: items[3].parse().map_err(|_e| { |
250 | 0 | NomErr::Failure(NomError::from_external_error( |
251 | 0 | input, |
252 | 0 | ErrorKind::Digit, |
253 | 0 | "Failed to parse scaling_shift", |
254 | 0 | )) |
255 | 0 | })?, |
256 | 0 | chroma_scaling_from_luma: items[4].parse::<u8>().map_err(|_e| { |
257 | 0 | NomErr::Failure(NomError::from_external_error( |
258 | 0 | input, |
259 | 0 | ErrorKind::Digit, |
260 | 0 | "Failed to parse chroma_scaling_from_luma", |
261 | 0 | )) |
262 | 0 | })? > 0, |
263 | 0 | overlap_flag: items[5].parse::<u8>().map_err(|_e| { |
264 | 0 | NomErr::Failure(NomError::from_external_error( |
265 | 0 | input, |
266 | 0 | ErrorKind::Digit, |
267 | 0 | "Failed to parse overlap_flag", |
268 | 0 | )) |
269 | 0 | })? > 0, |
270 | 0 | cb_mult: items[6].parse().map_err(|_e| { |
271 | 0 | NomErr::Failure(NomError::from_external_error( |
272 | 0 | input, |
273 | 0 | ErrorKind::Digit, |
274 | 0 | "Failed to parse cb_mult", |
275 | 0 | )) |
276 | 0 | })?, |
277 | 0 | cb_luma_mult: items[7].parse().map_err(|_e| { |
278 | 0 | NomErr::Failure(NomError::from_external_error( |
279 | 0 | input, |
280 | 0 | ErrorKind::Digit, |
281 | 0 | "Failed to parse cb_luma_mult", |
282 | 0 | )) |
283 | 0 | })?, |
284 | 0 | cb_offset: items[8].parse().map_err(|_e| { |
285 | 0 | NomErr::Failure(NomError::from_external_error( |
286 | 0 | input, |
287 | 0 | ErrorKind::Digit, |
288 | 0 | "Failed to parse cb_offset", |
289 | 0 | )) |
290 | 0 | })?, |
291 | 0 | cr_mult: items[9].parse().map_err(|_e| { |
292 | 0 | NomErr::Failure(NomError::from_external_error( |
293 | 0 | input, |
294 | 0 | ErrorKind::Digit, |
295 | 0 | "Failed to parse cr_mult", |
296 | 0 | )) |
297 | 0 | })?, |
298 | 0 | cr_luma_mult: items[10].parse().map_err(|_e| { |
299 | 0 | NomErr::Failure(NomError::from_external_error( |
300 | 0 | input, |
301 | 0 | ErrorKind::Digit, |
302 | 0 | "Failed to parse cr_luma_mult", |
303 | 0 | )) |
304 | 0 | })?, |
305 | 0 | cr_offset: items[11].parse().map_err(|_e| { |
306 | 0 | NomErr::Failure(NomError::from_external_error( |
307 | 0 | input, |
308 | 0 | ErrorKind::Digit, |
309 | 0 | "Failed to parse cr_offset", |
310 | 0 | )) |
311 | 0 | })?, |
312 | | }; |
313 | 0 | Ok(parsed) |
314 | 0 | }, |
315 | 0 | )(input)?; |
316 | | |
317 | 0 | if params.scaling_shift < 8 || params.scaling_shift > 11 { |
318 | 0 | return Err(NomErr::Failure(NomError::from_external_error( |
319 | 0 | input, |
320 | 0 | ErrorKind::Verify, |
321 | 0 | "scaling_shift must be between 8 and 11", |
322 | 0 | ))); |
323 | 0 | } |
324 | 0 | if params.ar_coeff_lag > 3 { |
325 | 0 | return Err(NomErr::Failure(NomError::from_external_error( |
326 | 0 | input, |
327 | 0 | ErrorKind::Verify, |
328 | 0 | "ar_coeff_lag must be between 0 and 3", |
329 | 0 | ))); |
330 | 0 | } |
331 | 0 | if params.ar_coeff_shift < 6 || params.ar_coeff_shift > 9 { |
332 | 0 | return Err(NomErr::Failure(NomError::from_external_error( |
333 | 0 | input, |
334 | 0 | ErrorKind::Verify, |
335 | 0 | "ar_coeff_shift must be between 6 and 9", |
336 | 0 | ))); |
337 | 0 | } |
338 | 0 |
|
339 | 0 | Ok((input, params)) |
340 | 0 | } |
341 | | |
342 | 0 | fn s_y_params(input: &str) -> IResult<&str, ArrayVec<[u8; 2], NUM_Y_POINTS>> { |
343 | 0 | let (input, values) = map_res::<_, _, _, _, NomErr<NomError<&str>>, _, _>( |
344 | 0 | line(preceded( |
345 | 0 | tag("sY"), |
346 | 0 | preceded(space1, separated_list1(space1, digit1)), |
347 | 0 | )), |
348 | 0 | |items: Vec<&str>| { |
349 | 0 | let mut parsed = Vec::with_capacity(items.len()); |
350 | 0 | for item in items { |
351 | 0 | parsed.push(item.parse::<u8>().map_err(|_e| { |
352 | 0 | NomErr::Failure(NomError::from_external_error( |
353 | 0 | input, |
354 | 0 | ErrorKind::Digit, |
355 | 0 | "Failed to parse Y-plane points", |
356 | 0 | )) |
357 | 0 | })?); |
358 | | } |
359 | 0 | Ok(parsed) |
360 | 0 | }, |
361 | 0 | )(input)?; |
362 | | |
363 | 0 | let len = values[0] as usize; |
364 | 0 | if values.len() != len * 2 + 1 { |
365 | 0 | return Err(NomErr::Failure(NomError::from_external_error( |
366 | 0 | input, |
367 | 0 | ErrorKind::Verify, |
368 | 0 | format!( |
369 | 0 | "Expected {} Y-plane points, got {}", |
370 | 0 | len * 2, |
371 | 0 | values.len() - 1 |
372 | 0 | ), |
373 | 0 | ))); |
374 | 0 | } |
375 | 0 |
|
376 | 0 | Ok(( |
377 | 0 | input, |
378 | 0 | values[1..] |
379 | 0 | .chunks_exact(2) |
380 | 0 | .map(|chunk| [chunk[0], chunk[1]]) |
381 | 0 | .collect(), |
382 | 0 | )) |
383 | 0 | } |
384 | | |
385 | 0 | fn s_cb_params(input: &str) -> IResult<&str, ArrayVec<[u8; 2], NUM_UV_POINTS>> { |
386 | 0 | let (input, values) = map_res::<_, _, _, _, NomErr<NomError<&str>>, _, _>( |
387 | 0 | line(preceded( |
388 | 0 | tag("sCb"), |
389 | 0 | preceded(space1, separated_list1(space1, digit1)), |
390 | 0 | )), |
391 | 0 | |items: Vec<&str>| { |
392 | 0 | let mut parsed = Vec::with_capacity(items.len()); |
393 | 0 | for item in items { |
394 | 0 | parsed.push(item.parse::<u8>().map_err(|_e| { |
395 | 0 | NomErr::Failure(NomError::from_external_error( |
396 | 0 | input, |
397 | 0 | ErrorKind::Digit, |
398 | 0 | "Failed to parse Cb-plane points", |
399 | 0 | )) |
400 | 0 | })?); |
401 | | } |
402 | 0 | Ok(parsed) |
403 | 0 | }, |
404 | 0 | )(input)?; |
405 | | |
406 | 0 | let len = values[0] as usize; |
407 | 0 | if values.len() != len * 2 + 1 { |
408 | 0 | return Err(NomErr::Failure(NomError::from_external_error( |
409 | 0 | input, |
410 | 0 | ErrorKind::Verify, |
411 | 0 | format!( |
412 | 0 | "Expected {} Cb-plane points, got {}", |
413 | 0 | len * 2, |
414 | 0 | values.len() - 1 |
415 | 0 | ), |
416 | 0 | ))); |
417 | 0 | } |
418 | 0 |
|
419 | 0 | Ok(( |
420 | 0 | input, |
421 | 0 | values[1..] |
422 | 0 | .chunks_exact(2) |
423 | 0 | .map(|chunk| [chunk[0], chunk[1]]) |
424 | 0 | .collect(), |
425 | 0 | )) |
426 | 0 | } |
427 | | |
428 | 0 | fn s_cr_params(input: &str) -> IResult<&str, ArrayVec<[u8; 2], NUM_UV_POINTS>> { |
429 | 0 | let (input, values) = map_res::<_, _, _, _, NomErr<NomError<&str>>, _, _>( |
430 | 0 | line(preceded( |
431 | 0 | tag("sCr"), |
432 | 0 | preceded(space1, separated_list1(space1, digit1)), |
433 | 0 | )), |
434 | 0 | |items: Vec<&str>| { |
435 | 0 | let mut parsed = Vec::with_capacity(items.len()); |
436 | 0 | for item in items { |
437 | 0 | parsed.push(item.parse::<u8>().map_err(|_e| { |
438 | 0 | NomErr::Failure(NomError::from_external_error( |
439 | 0 | input, |
440 | 0 | ErrorKind::Digit, |
441 | 0 | "Failed to parse Cr-plane points", |
442 | 0 | )) |
443 | 0 | })?); |
444 | | } |
445 | 0 | Ok(parsed) |
446 | 0 | }, |
447 | 0 | )(input)?; |
448 | | |
449 | 0 | let len = values[0] as usize; |
450 | 0 | if values.len() != len * 2 + 1 { |
451 | 0 | return Err(NomErr::Failure(NomError::from_external_error( |
452 | 0 | input, |
453 | 0 | ErrorKind::Verify, |
454 | 0 | format!( |
455 | 0 | "Expected {} Cr-plane points, got {}", |
456 | 0 | len * 2, |
457 | 0 | values.len() - 1 |
458 | 0 | ), |
459 | 0 | ))); |
460 | 0 | } |
461 | 0 |
|
462 | 0 | Ok(( |
463 | 0 | input, |
464 | 0 | values[1..] |
465 | 0 | .chunks_exact(2) |
466 | 0 | .map(|chunk| [chunk[0], chunk[1]]) |
467 | 0 | .collect(), |
468 | 0 | )) |
469 | 0 | } |
470 | | |
471 | 0 | fn integer(input: &str) -> IResult<&str, &str> { |
472 | 0 | recognize(preceded(opt(char('-')), digit1))(input) |
473 | 0 | } |
474 | | |
475 | 0 | fn c_y_params(input: &str, count: usize) -> IResult<&str, ArrayVec<i8, NUM_Y_COEFFS>> { |
476 | 0 | let (input, values) = map_res::<_, _, _, _, NomErr<NomError<&str>>, _, _>( |
477 | 0 | line(preceded( |
478 | 0 | tag("cY"), |
479 | 0 | preceded(space0, separated_list0(multispace1, integer)), |
480 | 0 | )), |
481 | 0 | |items: Vec<&str>| { |
482 | 0 | let mut parsed = Vec::with_capacity(items.len()); |
483 | 0 | for item in items { |
484 | 0 | parsed.push(item.parse::<i8>().map_err(|_e| { |
485 | 0 | NomErr::Failure(NomError::from_external_error( |
486 | 0 | input, |
487 | 0 | ErrorKind::Digit, |
488 | 0 | "Failed to parse Y-plane coeffs", |
489 | 0 | )) |
490 | 0 | })?); |
491 | | } |
492 | 0 | Ok(parsed) |
493 | 0 | }, |
494 | 0 | )(input)?; |
495 | | |
496 | 0 | if values.len() != count { |
497 | 0 | return Err(NomErr::Failure(NomError::from_external_error( |
498 | 0 | input, |
499 | 0 | ErrorKind::Verify, |
500 | 0 | format!("Expected {} Y-plane coeffs, got {}", count, values.len()), |
501 | 0 | ))); |
502 | 0 | } |
503 | 0 |
|
504 | 0 | Ok((input, values.into_iter().collect())) |
505 | 0 | } |
506 | | |
507 | 0 | fn c_cb_params(input: &str, count: usize) -> IResult<&str, ArrayVec<i8, NUM_UV_COEFFS>> { |
508 | 0 | let (input, values) = map_res::<_, _, _, _, NomErr<NomError<&str>>, _, _>( |
509 | 0 | line(preceded( |
510 | 0 | tag("cCb"), |
511 | 0 | preceded(space1, separated_list1(multispace1, integer)), |
512 | 0 | )), |
513 | 0 | |items: Vec<&str>| { |
514 | 0 | let mut parsed = Vec::with_capacity(items.len()); |
515 | 0 | for item in items { |
516 | 0 | parsed.push(item.parse::<i8>().map_err(|_e| { |
517 | 0 | NomErr::Failure(NomError::from_external_error( |
518 | 0 | input, |
519 | 0 | ErrorKind::Digit, |
520 | 0 | "Failed to parse Cb-plane coeffs", |
521 | 0 | )) |
522 | 0 | })?); |
523 | | } |
524 | 0 | Ok(parsed) |
525 | 0 | }, |
526 | 0 | )(input)?; |
527 | | |
528 | 0 | if values.len() != count + 1 { |
529 | 0 | return Err(NomErr::Failure(NomError::from_external_error( |
530 | 0 | input, |
531 | 0 | ErrorKind::Verify, |
532 | 0 | format!( |
533 | 0 | "Expected {} Cb-plane coeffs, got {}", |
534 | 0 | count + 1, |
535 | 0 | values.len() |
536 | 0 | ), |
537 | 0 | ))); |
538 | 0 | } |
539 | 0 |
|
540 | 0 | Ok((input, values.into_iter().collect())) |
541 | 0 | } |
542 | | |
543 | 0 | fn c_cr_params(input: &str, count: usize) -> IResult<&str, ArrayVec<i8, NUM_UV_COEFFS>> { |
544 | 0 | let (input, values) = map_res::<_, _, _, _, NomErr<NomError<&str>>, _, _>( |
545 | 0 | line(preceded( |
546 | 0 | tag("cCr"), |
547 | 0 | preceded(space1, separated_list1(multispace1, integer)), |
548 | 0 | )), |
549 | 0 | |items: Vec<&str>| { |
550 | 0 | let mut parsed = Vec::with_capacity(items.len()); |
551 | 0 | for item in items { |
552 | 0 | parsed.push(item.parse::<i8>().map_err(|_e| { |
553 | 0 | NomErr::Failure(NomError::from_external_error( |
554 | 0 | input, |
555 | 0 | ErrorKind::Digit, |
556 | 0 | "Failed to parse Cr-plane coeffs", |
557 | 0 | )) |
558 | 0 | })?); |
559 | | } |
560 | 0 | Ok(parsed) |
561 | 0 | }, |
562 | 0 | )(input)?; |
563 | | |
564 | 0 | if values.len() != count + 1 { |
565 | 0 | return Err(NomErr::Failure(NomError::from_external_error( |
566 | 0 | input, |
567 | 0 | ErrorKind::Verify, |
568 | 0 | format!( |
569 | 0 | "Expected {} Cr-plane coeffs, got {}", |
570 | 0 | count + 1, |
571 | 0 | values.len() |
572 | 0 | ), |
573 | 0 | ))); |
574 | 0 | } |
575 | 0 |
|
576 | 0 | Ok((input, values.into_iter().collect())) |
577 | 0 | } |
578 | | |
579 | | #[test] |
580 | | fn parse_luma_only_table() { |
581 | | // This is the luma-only table format generated by |
582 | | // both aomenc's photon noise utility and by av1an. |
583 | | let input = r#"filmgrn1 |
584 | | E 0 9223372036854775807 1 7391 1 |
585 | | p 0 6 0 8 0 1 0 0 0 0 0 0 |
586 | | sY 14 0 20 20 5 39 4 59 3 78 3 98 3 118 3 137 3 157 3 177 3 196 3 216 4 235 4 255 4 |
587 | | sCb 0 |
588 | | sCr 0 |
589 | | cY |
590 | | cCb 0 |
591 | | cCr 0 |
592 | | "#; |
593 | | let expected = GrainTableSegment { |
594 | | start_time: 0, |
595 | | end_time: 9_223_372_036_854_775_807, |
596 | | scaling_points_y: ArrayVec::from([ |
597 | | [0, 20], |
598 | | [20, 5], |
599 | | [39, 4], |
600 | | [59, 3], |
601 | | [78, 3], |
602 | | [98, 3], |
603 | | [118, 3], |
604 | | [137, 3], |
605 | | [157, 3], |
606 | | [177, 3], |
607 | | [196, 3], |
608 | | [216, 4], |
609 | | [235, 4], |
610 | | [255, 4], |
611 | | ]), |
612 | | scaling_points_cb: ArrayVec::new(), |
613 | | scaling_points_cr: ArrayVec::new(), |
614 | | scaling_shift: 8, |
615 | | ar_coeff_lag: 0, |
616 | | ar_coeffs_y: ArrayVec::new(), |
617 | | ar_coeffs_cb: ArrayVec::try_from([0].as_slice()).expect("Arrayvec has capacity"), |
618 | | ar_coeffs_cr: ArrayVec::try_from([0].as_slice()).expect("Arrayvec has capacity"), |
619 | | ar_coeff_shift: 6, |
620 | | cb_mult: 0, |
621 | | cb_luma_mult: 0, |
622 | | cb_offset: 0, |
623 | | cr_mult: 0, |
624 | | cr_luma_mult: 0, |
625 | | cr_offset: 0, |
626 | | overlap_flag: true, |
627 | | chroma_scaling_from_luma: false, |
628 | | grain_scale_shift: 0, |
629 | | random_seed: 7391, |
630 | | }; |
631 | | let output = parse_grain_table(input).expect("Test failed"); |
632 | | assert_eq!(vec![expected], output); |
633 | | } |
634 | | |
635 | | #[test] |
636 | | fn parse_luma_chroma_table() { |
637 | | // This is the luma+chroma table format generated by |
638 | | // both aomenc's photon noise utility and by av1an. |
639 | | let input = r#"filmgrn1 |
640 | | E 0 9223372036854775807 1 7391 1 |
641 | | p 0 6 0 8 0 1 128 192 256 128 192 256 |
642 | | sY 14 0 0 20 4 39 3 59 3 78 3 98 3 118 4 137 4 157 4 177 4 196 4 216 5 235 5 255 5 |
643 | | sCb 10 0 0 28 0 57 0 85 0 113 0 142 0 170 0 198 0 227 0 255 1 |
644 | | sCr 10 0 0 28 0 57 0 85 0 113 0 142 0 170 0 198 0 227 0 255 1 |
645 | | cY |
646 | | cCb 0 |
647 | | cCr 0 |
648 | | "#; |
649 | | let expected = GrainTableSegment { |
650 | | start_time: 0, |
651 | | end_time: 9_223_372_036_854_775_807, |
652 | | scaling_points_y: ArrayVec::from([ |
653 | | [0, 0], |
654 | | [20, 4], |
655 | | [39, 3], |
656 | | [59, 3], |
657 | | [78, 3], |
658 | | [98, 3], |
659 | | [118, 4], |
660 | | [137, 4], |
661 | | [157, 4], |
662 | | [177, 4], |
663 | | [196, 4], |
664 | | [216, 5], |
665 | | [235, 5], |
666 | | [255, 5], |
667 | | ]), |
668 | | scaling_points_cb: ArrayVec::from([ |
669 | | [0, 0], |
670 | | [28, 0], |
671 | | [57, 0], |
672 | | [85, 0], |
673 | | [113, 0], |
674 | | [142, 0], |
675 | | [170, 0], |
676 | | [198, 0], |
677 | | [227, 0], |
678 | | [255, 1], |
679 | | ]), |
680 | | scaling_points_cr: ArrayVec::from([ |
681 | | [0, 0], |
682 | | [28, 0], |
683 | | [57, 0], |
684 | | [85, 0], |
685 | | [113, 0], |
686 | | [142, 0], |
687 | | [170, 0], |
688 | | [198, 0], |
689 | | [227, 0], |
690 | | [255, 1], |
691 | | ]), |
692 | | scaling_shift: 8, |
693 | | ar_coeff_lag: 0, |
694 | | ar_coeffs_y: ArrayVec::new(), |
695 | | ar_coeffs_cb: ArrayVec::try_from([0].as_slice()).expect("Arrayvec has capacity"), |
696 | | ar_coeffs_cr: ArrayVec::try_from([0].as_slice()).expect("Arrayvec has capacity"), |
697 | | ar_coeff_shift: 6, |
698 | | cb_mult: 128, |
699 | | cb_luma_mult: 192, |
700 | | cb_offset: 256, |
701 | | cr_mult: 128, |
702 | | cr_luma_mult: 192, |
703 | | cr_offset: 256, |
704 | | overlap_flag: true, |
705 | | chroma_scaling_from_luma: false, |
706 | | grain_scale_shift: 0, |
707 | | random_seed: 7391, |
708 | | }; |
709 | | let output = parse_grain_table(input).expect("Test failed"); |
710 | | assert_eq!(vec![expected], output); |
711 | | } |
712 | | |
713 | | #[test] |
714 | | fn parse_complex_table() { |
715 | | let input = r#"filmgrn1 |
716 | | E 0 417083 1 7391 1 |
717 | | p 3 7 0 11 0 1 128 192 256 128 192 256 |
718 | | sY 6 0 53 13 53 40 64 94 49 121 46 255 46 |
719 | | sCb 2 0 14 255 13 |
720 | | sCr 2 0 12 255 14 |
721 | | cY 1 -4 1 4 8 3 -2 -6 9 14 -27 -25 -2 4 5 15 -80 94 28 -3 -2 6 -47 121 |
722 | | cCb -3 1 -4 6 -1 2 -2 1 11 -10 -2 -16 -1 3 -2 -14 -26 65 19 -3 -5 2 -6 75 -1 |
723 | | cCr 0 0 -4 8 -1 0 1 2 -1 -9 4 -7 -5 -2 -5 -14 0 45 18 3 -3 4 8 49 5 |
724 | | E 417083 7090416 1 0 1 |
725 | | p 3 7 0 11 0 1 128 192 256 128 192 256 |
726 | | sY 4 0 46 40 54 108 39 255 38 |
727 | | sCb 2 0 14 255 14 |
728 | | sCr 2 0 12 255 14 |
729 | | cY 1 -4 1 5 8 4 -2 -6 9 13 -28 -28 -5 5 5 13 -76 91 32 -1 -3 7 -50 124 |
730 | | cCb -2 1 -3 3 -2 1 -1 2 8 -10 0 -12 -2 2 -1 -14 -20 61 18 -1 -4 -2 -1 70 -1 |
731 | | cCr 0 0 -3 6 -1 -1 0 1 -2 -8 6 -4 -5 -2 -6 -12 4 41 17 4 -2 3 13 44 5 |
732 | | E 7090416 7507500 1 0 1 |
733 | | p 3 7 0 11 0 1 128 192 256 128 192 256 |
734 | | sY 4 0 54 40 64 108 46 255 44 |
735 | | sCb 2 0 14 255 13 |
736 | | sCr 2 0 12 255 14 |
737 | | cY 1 -4 2 3 7 3 -2 -6 9 14 -26 -25 -3 5 6 15 -81 95 27 -3 -3 5 -46 121 |
738 | | cCb -2 1 -4 4 -2 1 -1 2 9 -12 3 -13 -1 2 -2 -16 -26 66 17 -2 -5 -1 1 73 0 |
739 | | cCr 1 -1 -5 8 -1 -1 1 1 -3 -9 9 -5 -6 -2 -7 -14 1 44 17 3 -3 5 15 46 4 |
740 | | E 7507500 10010000 1 0 1 |
741 | | p 3 7 0 11 0 1 128 192 256 128 192 256 |
742 | | sY 4 0 49 40 59 108 43 255 41 |
743 | | sCb 2 0 14 255 14 |
744 | | sCr 2 0 13 255 15 |
745 | | cY 1 -4 0 6 8 3 -2 -5 8 14 -29 -26 -3 4 3 15 -76 92 29 -2 -3 8 -49 121 |
746 | | cCb -3 0 -3 6 0 1 -2 1 10 -9 -4 -15 -1 2 -1 -13 -22 62 20 -3 -4 2 -7 73 -1 |
747 | | cCr -1 0 -3 6 0 0 0 2 0 -9 2 -7 -5 -1 -4 -14 0 45 19 2 -2 3 7 50 4 |
748 | | E 10010000 13346666 1 0 1 |
749 | | p 3 7 0 11 0 1 128 192 256 128 192 256 |
750 | | sY 6 0 33 27 39 40 53 54 55 108 52 255 52 |
751 | | sCb 2 0 16 255 14 |
752 | | sCr 2 0 11 255 12 |
753 | | cY 1 -4 1 5 9 4 -2 -7 12 11 -27 -30 -5 5 6 10 -73 89 35 -1 -3 6 -49 124 |
754 | | cCb -2 0 -2 1 -2 1 -2 0 9 -9 -2 -14 -1 2 0 -11 -26 65 18 -2 -4 -2 -8 75 -5 |
755 | | cCr 0 0 -4 5 -2 0 1 3 -1 -9 6 -5 -5 -1 -6 -14 1 43 18 4 -3 3 13 49 3 |
756 | | E 13346666 16683333 1 0 1 |
757 | | p 3 7 0 11 0 1 128 192 256 128 192 256 |
758 | | sY 6 0 36 27 42 40 58 54 60 108 57 255 57 |
759 | | sCb 2 0 15 255 14 |
760 | | sCr 4 0 11 40 17 94 13 255 13 |
761 | | cY 1 -4 1 5 8 3 -2 -6 10 12 -27 -27 -4 4 5 12 -73 90 32 -2 -3 6 -47 121 |
762 | | cCb -2 0 -3 4 -1 1 -2 0 10 -9 -2 -14 1 3 -1 -10 -24 62 16 -2 -4 0 -6 72 -7 |
763 | | cCr 0 0 -3 6 -1 0 1 3 1 -9 3 -7 -5 -1 -5 -14 -2 46 19 2 -3 3 7 54 3 |
764 | | E 16683333 17100416 1 0 1 |
765 | | p 3 7 0 11 0 1 128 192 256 128 192 256 |
766 | | sY 7 0 41 13 41 27 49 40 66 54 68 108 65 255 65 |
767 | | sCb 2 0 18 255 14 |
768 | | sCr 4 0 11 40 18 67 14 255 13 |
769 | | cY 0 -3 1 4 7 3 -2 -5 7 13 -27 -23 -3 4 5 15 -79 94 26 -3 -2 5 -45 120 |
770 | | cCb -1 -2 -1 1 0 0 -3 -2 12 -6 -3 -15 3 2 2 -8 -42 75 12 -3 -4 -2 -8 82 -3 |
771 | | cCr 0 0 -5 7 -2 0 1 3 0 -11 6 -7 -5 -1 -6 -15 -5 48 18 2 -3 3 10 55 2 |
772 | | E 17100416 20020000 1 0 1 |
773 | | p 3 7 0 11 0 1 128 192 256 128 192 256 |
774 | | sY 6 0 37 27 44 40 61 54 63 108 60 255 60 |
775 | | sCb 2 0 14 255 14 |
776 | | sCr 4 0 11 40 18 94 13 255 13 |
777 | | cY 1 -3 0 6 7 2 -1 -5 7 13 -28 -25 -2 3 3 13 -73 91 29 -2 -2 7 -47 119 |
778 | | cCb -2 -1 -3 4 0 1 -2 -1 11 -7 -6 -15 1 2 -1 -9 -25 63 16 -3 -4 2 -11 73 -8 |
779 | | cCr -1 1 -2 6 0 1 0 2 3 -9 -2 -10 -4 0 -3 -14 -6 50 20 0 -3 3 -1 59 3 |
780 | | E 20020000 9223372036854775807 1 0 1 |
781 | | p 3 6 0 11 0 1 128 192 256 128 192 256 |
782 | | sY 6 0 32 27 37 40 50 54 52 121 49 255 49 |
783 | | sCb 4 0 21 40 23 81 17 255 15 |
784 | | sCr 2 0 11 255 12 |
785 | | cY 1 -3 1 2 5 3 -2 -6 8 6 -12 -18 -2 3 5 7 -42 44 21 -3 -1 4 -29 67 |
786 | | cCb -1 0 1 0 -1 0 -1 0 5 -4 -3 -9 1 1 2 -4 -21 39 10 -2 -3 -2 -7 44 1 |
787 | | cCr 1 0 -3 2 -3 -1 0 1 -1 -4 5 -2 -1 -1 -5 -6 3 20 10 4 -2 0 9 23 -1"#; |
788 | | let output = parse_grain_table(input); |
789 | | assert!(output.is_ok()); |
790 | | } |