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