]> git.nihav.org Git - nihav.git/blame - nihav-commonfmt/src/codecs/cinepakenc.rs
avimux: do not record palette change chunks in OpenDML index
[nihav.git] / nihav-commonfmt / src / codecs / cinepakenc.rs
CommitLineData
a178c22c
KS
1use nihav_core::codecs::*;
2use nihav_core::io::byteio::*;
3use nihav_codec_support::vq::*;
4
5#[derive(Default,Clone,Copy,PartialEq,Debug)]
6struct YUVCode {
7 y: [u8; 4],
8 u: u8,
9 v: u8,
10}
11impl VQElement for YUVCode {
12 fn dist(&self, rval: Self) -> u32 {
13 let mut ysum = 0;
14 for (y0, y1) in self.y.iter().zip(rval.y.iter()) {
15 let yd = i32::from(*y0) - i32::from(*y1);
16 ysum += yd * yd;
17 }
18 let ud = i32::from(self.u) - i32::from(rval.u);
19 let vd = i32::from(self.v) - i32::from(rval.v);
20 (ysum + ud * ud + vd * vd) as u32
21 }
22 fn min_cw() -> Self { YUVCode { y: [0; 4], u: 0, v: 0 } }
23 fn max_cw() -> Self { YUVCode { y: [255; 4], u: 255, v: 255 } }
24 fn min(&self, rval: Self) -> Self {
25 let mut ycode = YUVCode::default();
26 for i in 0..4 {
27 ycode.y[i] = self.y[i].min(rval.y[i]);
28 }
29 ycode.u = self.u.min(rval.u);
30 ycode.v = self.v.min(rval.v);
31 ycode
32 }
33 fn max(&self, rval: Self) -> Self {
34 let mut ycode = YUVCode::default();
35 for i in 0..4 {
36 ycode.y[i] = self.y[i].max(rval.y[i]);
37 }
38 ycode.u = self.u.max(rval.u);
39 ycode.v = self.v.max(rval.v);
40 ycode
41 }
42 fn num_components() -> usize { 6 }
43 fn sort_by_component(arr: &mut [Self], component: usize) {
44 let mut counts = [0; 256];
45 for entry in arr.iter() {
46 let idx = match component {
47 0 | 1 | 2 | 3 => entry.y[component],
48 4 => entry.u,
49 _ => entry.v,
50 } as usize;
51 counts[idx] += 1;
52 }
53 let mut offs = [0; 256];
54 for i in 0..255 {
55 offs[i + 1] = offs[i] + counts[i];
56 }
57 let mut dst = vec![YUVCode::default(); arr.len()];
58 for entry in arr.iter() {
59 let idx = match component {
60 0 | 1 | 2 | 3 => entry.y[component],
61 4 => entry.u,
62 _ => entry.v,
63 } as usize;
64 dst[offs[idx]] = *entry;
65 offs[idx] += 1;
66 }
67 arr.copy_from_slice(dst.as_slice());
68 }
69 fn max_dist_component(min: &Self, max: &Self) -> usize {
70 let mut comp = 0;
71 let mut diff = 0;
72 for i in 0..4 {
73 let d = u32::from(max.y[i]) - u32::from(min.y[i]);
74 if d > diff {
75 diff = d;
76 comp = i;
77 }
78 }
79 let ud = u32::from(max.u) - u32::from(min.u);
80 if ud > diff {
81 diff = ud;
82 comp = 4;
83 }
84 let vd = u32::from(max.v) - u32::from(min.v);
85 if vd > diff {
86 comp = 5;
87 }
88 comp
89 }
90}
91
92#[derive(Default)]
93struct YUVCodeSum {
94 ysum: [u64; 4],
95 usum: u64,
96 vsum: u64,
97 count: u64,
98}
99
100impl VQElementSum<YUVCode> for YUVCodeSum {
101 fn zero() -> Self { Self::default() }
102 fn add(&mut self, rval: YUVCode, count: u64) {
103 for i in 0..4 {
104 self.ysum[i] += u64::from(rval.y[i]) * count;
105 }
106 self.usum += u64::from(rval.u) * count;
107 self.vsum += u64::from(rval.v) * count;
108 self.count += count;
109 }
110 fn get_centroid(&self) -> YUVCode {
111 if self.count != 0 {
112 let mut ycode = YUVCode::default();
113 for i in 0..4 {
114 ycode.y[i] = ((self.ysum[i] + self.count / 2) / self.count) as u8;
115 }
116 ycode.u = ((self.usum + self.count / 2) / self.count) as u8;
117 ycode.v = ((self.vsum + self.count / 2) / self.count) as u8;
118 ycode
119 } else {
120 YUVCode::default()
121 }
122 }
123}
124
125struct RNG {
126 seed: u32,
127}
128
129impl RNG {
130 fn new() -> Self { Self { seed: 0x12345678 } }
131 fn next(&mut self) -> u8 {
132 let mut x = self.seed;
133 x ^= x.wrapping_shl(13);
134 x ^= x >> 17;
135 self.seed = x;
136 (self.seed >> 24) as u8
137 }
138 fn fill_entry(&mut self, entry: &mut YUVCode) {
139 for y in entry.y.iter_mut() {
140 *y = self.next();
141 }
142 entry.u = self.next();
143 entry.v = self.next();
144 }
145}
146
147const GRAY_FORMAT: NAPixelFormaton = NAPixelFormaton {
148 model: ColorModel::YUV(YUVSubmodel::YUVJ),
149 components: 1,
150 comp_info: [Some(NAPixelChromaton{h_ss: 0, v_ss: 0, packed: false, depth: 8, shift: 0, comp_offs: 0, next_elem: 1}), None, None, None, None],
151 elem_size: 1,
152 be: true,
153 alpha: false,
154 palette: false,
155 };
156
157struct MaskWriter {
158 masks: Vec<u32>,
159 mask: u32,
160 pos: u8,
161}
162
163impl MaskWriter {
164 fn new() -> Self {
165 Self {
166 masks: Vec::new(),
167 mask: 0,
168 pos: 0,
169 }
170 }
171 fn reset(&mut self) {
37952415 172 self.masks.clear();
a178c22c
KS
173 self.mask = 0;
174 self.pos = 0;
175 }
176 fn put_v1(&mut self) {
177 self.mask <<= 1;
178 self.pos += 1;
179 if self.pos == 32 {
180 self.flush();
181 }
182 }
183 fn put_v4(&mut self) {
184 self.mask <<= 1;
185 self.mask |= 1;
186 self.pos += 1;
187 if self.pos == 32 {
188 self.flush();
189 }
190 }
191 fn put_inter(&mut self, skip: bool) {
192 self.mask <<= 1;
193 self.mask |= !skip as u32;
194 self.pos += 1;
195 if self.pos == 32 {
196 self.flush();
197 }
198 }
199 fn flush(&mut self) {
200 self.masks.push(self.mask);
201 self.mask = 0;
202 self.pos = 0;
203 }
204 fn end(&mut self) {
205 if self.pos == 0 { return; }
206 while self.pos < 32 {
207 self.mask <<= 1;
208 self.pos += 1;
209 }
210 self.flush();
211 }
212}
213
3c406629
KS
214#[derive(Clone,Copy,PartialEq)]
215enum QuantMode {
216 ELBG,
42ef5325 217 Fast,
3c406629
KS
218 MedianCut,
219}
220
61cab15b 221impl std::string::ToString for QuantMode {
3c406629
KS
222 fn to_string(&self) -> String {
223 match *self {
224 QuantMode::ELBG => "elbg".to_string(),
42ef5325 225 QuantMode::Fast => "fast".to_string(),
3c406629
KS
226 QuantMode::MedianCut => "mediancut".to_string(),
227 }
228 }
229}
230
6064de24
KS
231#[derive(Clone,Copy,PartialEq)]
232enum CodingMode {
233 Skip,
234 V1,
235 V4
236}
237
a178c22c
KS
238struct CinepakEncoder {
239 stream: Option<NAStreamRef>,
240 lastfrm: Option<NAVideoBufferRef<u8>>,
241 pkt: Option<NAPacket>,
242 frmcount: u8,
3c406629
KS
243 key_int: u8,
244 qmode: QuantMode,
a178c22c 245 quality: u8,
6064de24 246 refine: bool,
a178c22c 247 nstrips: usize,
c6f14420 248 force_v1: bool,
9a57fda1 249 cur_strip: usize,
a178c22c
KS
250 v1_entries: Vec<YUVCode>,
251 v4_entries: Vec<YUVCode>,
9a57fda1
KS
252 v1_cb: Vec<[YUVCode; 256]>,
253 v4_cb: Vec<[YUVCode; 256]>,
254 v1_cur_cb: Vec<[YUVCode; 256]>,
255 v4_cur_cb: Vec<[YUVCode; 256]>,
592d2889
KS
256 v1_len: usize,
257 v4_len: usize,
a178c22c
KS
258 v1_idx: Vec<u8>,
259 v4_idx: Vec<u8>,
260 grayscale: bool,
261 rng: RNG,
262 masks: MaskWriter,
263 skip_dist: Vec<u32>,
42ef5325 264 fst_bins: [Vec<YUVCode>; 4],
6064de24
KS
265 v1_cand: Vec<YUVCode>,
266 v4_cand: Vec<YUVCode>,
267 cmode: Vec<CodingMode>,
a178c22c
KS
268}
269
270fn avg4(a: u8, b: u8, c: u8, d: u8) -> u8 {
271 ((u16::from(a) + u16::from(b) + u16::from(c) + u16::from(d) + 3) >> 2) as u8
272}
273
42ef5325
KS
274fn variance(a: u8, mean: u8) -> u32 {
275 if a >= mean {
276 u32::from(a - mean) * u32::from(a - mean)
277 } else {
278 u32::from(mean - a) * u32::from(mean - a)
279 }
280}
281
a178c22c
KS
282fn patch_size(bw: &mut ByteWriter, pos: u64) -> EncoderResult<()> {
283 let size = bw.tell() - pos;
284 bw.seek(SeekFrom::Current(-((size + 3) as i64)))?;
285 bw.write_u24be((size + 4) as u32)?;
286 bw.seek(SeekFrom::End(0))?;
287 Ok(())
288}
289
7460b53e
KS
290fn elbg_quant(entries: &[YUVCode], codebook: &mut [YUVCode]) -> usize {
291 let cb_len = quantise_median_cut::<YUVCode, YUVCodeSum>(entries, codebook);
292 if cb_len < codebook.len() {
293 cb_len
294 } else {
295 let mut elbg: ELBG<YUVCode, YUVCodeSum> = ELBG::new(codebook);
296 elbg.quantise(entries, codebook)
297 }
298}
299
42ef5325
KS
300fn quant_fast(bins: &mut [Vec<YUVCode>; 4], entries: &[YUVCode], codebook: &mut [YUVCode]) -> usize {
301 for bin in bins.iter_mut() {
302 bin.clear();
303 }
304 for &entry in entries.iter() {
305 let y_avg = avg4(entry.y[0], entry.y[1], entry.y[2], entry.y[3]);
306 let dist = entry.y.iter().fold(0u32, |acc, &x| acc + variance(x, y_avg));
307 let ilog = if dist == 0 { 0 } else { 32 - dist.leading_zeros() };
308 let bin = match ilog {
309 0..=3 => &mut bins[0],
310 4..=7 => &mut bins[1],
311 8..=11 => &mut bins[2],
312 _ => &mut bins[3],
313 };
314 bin.push(entry);
315 }
316 let mut free_cw = codebook.len();
317 let mut entries_left = entries.len();
318 let mut offset = 0;
319 for bin in bins.iter() {
320 if bin.is_empty() {
321 continue;
322 }
323 if free_cw == 0 || entries_left == 0 {
324 break;
325 }
326 let target = (free_cw * bin.len() + entries_left - 1) / entries_left;
327 let cur_len = elbg_quant(bin, &mut codebook[offset..][..target]);
328 offset += cur_len;
329 free_cw -= cur_len;
330 entries_left -= bin.len();
331 }
332 offset
333}
334
ba8718ff 335#[allow(clippy::collapsible_else_if)]
a178c22c
KS
336impl CinepakEncoder {
337 fn new() -> Self {
338 Self {
339 stream: None,
340 pkt: None,
341 lastfrm: None,
342 frmcount: 0,
42ef5325 343 qmode: QuantMode::Fast,
3c406629 344 key_int: 25,
a178c22c 345 quality: 0,
6064de24 346 refine: false,
a178c22c 347 nstrips: 2,
c6f14420 348 force_v1: false,
9a57fda1 349 cur_strip: 0,
a178c22c
KS
350 v1_entries: Vec::new(),
351 v4_entries: Vec::new(),
9a57fda1
KS
352 v1_cb: Vec::with_capacity(2),
353 v4_cb: Vec::with_capacity(2),
354 v1_cur_cb: Vec::with_capacity(2),
355 v4_cur_cb: Vec::with_capacity(2),
592d2889
KS
356 v1_len: 0,
357 v4_len: 0,
a178c22c
KS
358 grayscale: false,
359 rng: RNG::new(),
360 v1_idx: Vec::new(),
361 v4_idx: Vec::new(),
362 masks: MaskWriter::new(),
363 skip_dist: Vec::new(),
42ef5325 364 fst_bins: [Vec::new(), Vec::new(), Vec::new(), Vec::new()],
6064de24
KS
365 v1_cand: Vec::new(),
366 v4_cand: Vec::new(),
367 cmode: Vec::new(),
a178c22c
KS
368 }
369 }
370 fn read_strip(&mut self, in_frm: &NAVideoBuffer<u8>, start: usize, end: usize) {
371 let ystride = in_frm.get_stride(0);
372 let mut yoff = in_frm.get_offset(0) + start * ystride;
373 let ustride = in_frm.get_stride(1);
374 let mut uoff = in_frm.get_offset(1) + start / 2 * ustride;
375 let vstride = in_frm.get_stride(2);
376 let mut voff = in_frm.get_offset(2) + start / 2 * vstride;
377 let (width, _) = in_frm.get_dimensions(0);
378 let data = in_frm.get_data();
37952415
KS
379 self.v1_entries.clear();
380 self.v4_entries.clear();
a178c22c
KS
381 for _ in (start..end).step_by(4) {
382 for x in (0..width).step_by(4) {
383 let mut yblk = [0; 16];
384 let mut ublk = [128; 4];
385 let mut vblk = [128; 4];
386 for j in 0..4 {
387 for i in 0..4 {
388 yblk[i + j * 4] = data[yoff + x + i + j * ystride];
389 }
390 }
391 if !self.grayscale {
392 for j in 0..2 {
393 for i in 0..2 {
394 ublk[i + j * 2] = data[uoff + x / 2 + i + j * ustride];
395 vblk[i + j * 2] = data[voff + x / 2 + i + j * vstride];
396 }
397 }
398 }
399 self.v1_entries.push(YUVCode {
400 y: [avg4(yblk[ 0], yblk[ 1], yblk[ 4], yblk[ 5]),
401 avg4(yblk[ 2], yblk[ 3], yblk[ 6], yblk[ 7]),
402 avg4(yblk[ 8], yblk[ 9], yblk[12], yblk[13]),
403 avg4(yblk[10], yblk[11], yblk[14], yblk[15])],
404 u: avg4(ublk[0], ublk[1], ublk[2], ublk[3]),
405 v: avg4(vblk[0], vblk[1], vblk[2], vblk[3]),
406 });
407 for i in 0..4 {
408 let yidx = (i & 1) * 2 + (i & 2) * 4;
409 self.v4_entries.push(YUVCode {
410 y: [ yblk[yidx], yblk[yidx + 1], yblk[yidx + 4], yblk[yidx + 5] ],
411 u: ublk[i],
412 v: vblk[i],
413 });
414 }
415 }
416 yoff += ystride * 4;
417 uoff += ustride * 2;
418 voff += vstride * 2;
419 }
420 }
592d2889 421 fn find_nearest(codebook: &[YUVCode], code: YUVCode) -> (u8, u32) {
08e0a8bf 422 let mut min_dist = u32::MAX;
a178c22c
KS
423 let mut idx = 0;
424 for (i, cw) in codebook.iter().enumerate() {
425 let dist = cw.dist(code);
426 if dist < min_dist {
427 min_dist = dist;
428 idx = i;
429 if dist == 0 {
430 break;
431 }
432 }
433 }
434 (idx as u8, min_dist)
435 }
9f7faaf3 436 fn can_update_cb(new_cb: &[YUVCode], old_cb: &[YUVCode], cb_size: usize) -> bool {
a178c22c
KS
437 let mut skip_count = 0;
438 for (new, old) in new_cb.iter().zip(old_cb.iter()) {
439 if new == old {
440 skip_count += 1;
441 }
442 }
9f7faaf3
KS
443 let full_size = cb_size * new_cb.len();
444 let upd_size = cb_size * (new_cb.len() - skip_count) + (new_cb.len() + 31) / 32 * 4;
a178c22c
KS
445 upd_size < full_size
446 }
9f7faaf3 447 fn write_cb(bw: &mut ByteWriter, mut id: u8, new_cb: &[YUVCode], old_cb: &[YUVCode], grayscale: bool, update: bool, num_elem: usize) -> EncoderResult<()> {
a178c22c
KS
448 if grayscale {
449 id |= 4;
450 }
451 if update {
452 id |= 1;
453 }
454 bw.write_byte(id)?;
455 bw.write_u24be(0)?;
456 let chunk_pos = bw.tell();
457 if !update {
9f7faaf3 458 for entry in new_cb.iter().take(num_elem) {
a178c22c
KS
459 bw.write_buf(&entry.y)?;
460 if !grayscale {
461 bw.write_byte(entry.u ^ 0x80)?;
462 bw.write_byte(entry.v ^ 0x80)?;
463 }
464 }
465 } else {
9f7faaf3
KS
466 let mut end = num_elem;
467 for (i, (ncw, ocw)) in new_cb.iter().zip(old_cb.iter()).enumerate().take(num_elem).rev() {
a178c22c
KS
468 if ncw == ocw {
469 end = i;
470 } else {
471 break;
472 }
473 }
474 for i in (0..end).step_by(32) {
475 let mut mask = 0;
476 for j in 0..32 {
477 mask <<= 1;
478 if new_cb[i + j] != old_cb[i + j] {
479 mask |= 1;
480 }
481 }
482 bw.write_u32be(mask)?;
483 for j in 0..32 {
484 if new_cb[i + j] == old_cb[i + j] { continue; }
485 bw.write_buf(&new_cb[i + j].y)?;
486 if !grayscale {
487 bw.write_byte(new_cb[i + j].u ^ 0x80)?;
488 bw.write_byte(new_cb[i + j].v ^ 0x80)?;
489 }
490 }
491 }
492 }
493 patch_size(bw, chunk_pos)?;
494 Ok(())
495 }
496 fn render_stripe(&mut self, intra: bool, start: usize, end: usize) {
497 if let Some(ref mut dst_frm) = self.lastfrm {
498 let ystride = dst_frm.get_stride(0);
499 let mut yoff = dst_frm.get_offset(0) + start * ystride;
500 let ustride = dst_frm.get_stride(1);
501 let mut uoff = dst_frm.get_offset(1) + start / 2 * ustride;
502 let vstride = dst_frm.get_stride(2);
503 let mut voff = dst_frm.get_offset(2) + start / 2 * vstride;
504 let (width, _) = dst_frm.get_dimensions(0);
505 let data = dst_frm.get_data_mut().unwrap();
506 let mut miter = self.masks.masks.iter();
507 let mut v1_iter = self.v1_idx.iter();
508 let mut v4_iter = self.v4_idx.iter();
509 let mut cur_mask = 0;
510 let mut cur_bit = 0;
511 for _ in (start..end).step_by(4) {
512 for x in (0..width).step_by(4) {
513 if cur_bit == 0 {
61cab15b 514 if !intra || !self.v1_idx.is_empty() {
a178c22c
KS
515 cur_mask = *miter.next().unwrap();
516 } else {
517 cur_mask = 0xFFFFFFFF;
518 }
519 cur_bit = 1 << 31;
520 }
521 if !intra {
522 if (cur_mask & cur_bit) == 0 {
523 cur_bit >>= 1;
524 continue;
525 }
526 cur_bit >>= 1;
527 if cur_bit == 0 {
528 cur_mask = *miter.next().unwrap();
529 cur_bit = 1 << 31;
530 }
531 }
532 if (cur_mask & cur_bit) == 0 {
533 let idx = *v1_iter.next().unwrap() as usize;
9a57fda1 534 let cb = &self.v1_cur_cb[self.cur_strip][idx];
a178c22c
KS
535
536 let mut coff = yoff + x;
537 data[coff] = cb.y[0]; data[coff + 1] = cb.y[0];
538 data[coff + 2] = cb.y[1]; data[coff + 3] = cb.y[1];
539 coff += ystride;
540 data[coff] = cb.y[0]; data[coff + 1] = cb.y[0];
541 data[coff + 2] = cb.y[1]; data[coff + 3] = cb.y[1];
542 coff += ystride;
543 data[coff] = cb.y[2]; data[coff + 1] = cb.y[2];
544 data[coff + 2] = cb.y[3]; data[coff + 3] = cb.y[3];
545 coff += ystride;
546 data[coff] = cb.y[2]; data[coff + 1] = cb.y[2];
547 data[coff + 2] = cb.y[3]; data[coff + 3] = cb.y[3];
548
549 if !self.grayscale {
550 let mut coff = uoff + x / 2;
551 data[coff] = cb.u; data[coff + 1] = cb.u;
552 coff += ustride;
553 data[coff] = cb.u; data[coff + 1] = cb.u;
554
555 let mut coff = voff + x / 2;
556 data[coff] = cb.v; data[coff + 1] = cb.v;
557 coff += vstride;
558 data[coff] = cb.v; data[coff + 1] = cb.v;
559 }
560 } else {
561 let idx0 = *v4_iter.next().unwrap() as usize;
9a57fda1 562 let cb0 = &self.v4_cur_cb[self.cur_strip][idx0];
a178c22c 563 let idx1 = *v4_iter.next().unwrap() as usize;
9a57fda1 564 let cb1 = &self.v4_cur_cb[self.cur_strip][idx1];
a178c22c 565 let idx2 = *v4_iter.next().unwrap() as usize;
9a57fda1 566 let cb2 = &self.v4_cur_cb[self.cur_strip][idx2];
a178c22c 567 let idx3 = *v4_iter.next().unwrap() as usize;
9a57fda1 568 let cb3 = &self.v4_cur_cb[self.cur_strip][idx3];
a178c22c
KS
569
570 let mut coff = yoff + x;
571 data[coff] = cb0.y[0]; data[coff + 1] = cb0.y[1];
572 data[coff + 2] = cb1.y[0]; data[coff + 3] = cb1.y[1];
573 coff += ystride;
574 data[coff] = cb0.y[2]; data[coff + 1] = cb0.y[3];
575 data[coff + 2] = cb1.y[2]; data[coff + 3] = cb1.y[3];
576 coff += ystride;
577 data[coff] = cb2.y[0]; data[coff + 1] = cb2.y[1];
578 data[coff + 2] = cb3.y[0]; data[coff + 3] = cb3.y[1];
579 coff += ystride;
580 data[coff] = cb2.y[2]; data[coff + 1] = cb2.y[3];
581 data[coff + 2] = cb3.y[2]; data[coff + 3] = cb3.y[3];
582
583 if !self.grayscale {
584 let mut coff = uoff + x / 2;
585 data[coff] = cb0.u; data[coff + 1] = cb1.u;
586 coff += ustride;
587 data[coff] = cb2.u; data[coff + 1] = cb3.u;
588
589 let mut coff = voff + x / 2;
590 data[coff] = cb0.v; data[coff + 1] = cb1.v;
591 coff += vstride;
592 data[coff] = cb2.v; data[coff + 1] = cb3.v;
593 }
594 }
595 cur_bit >>= 1;
596 }
597 yoff += ystride * 4;
598 uoff += ustride * 2;
599 voff += vstride * 2;
600 }
601 } else {
602 unreachable!();
603 }
604 }
605 fn calc_skip_dist(&mut self, in_frm: &NAVideoBuffer<u8>, start: usize, end: usize) {
37952415 606 self.skip_dist.clear();
a178c22c
KS
607 if let Some(ref ref_frm) = self.lastfrm {
608 let rystride = ref_frm.get_stride(0);
609 let mut ryoff = ref_frm.get_offset(0) + start * rystride;
610 let rustride = ref_frm.get_stride(1);
611 let mut ruoff = ref_frm.get_offset(1) + start / 2 * rustride;
612 let rvstride = ref_frm.get_stride(2);
613 let mut rvoff = ref_frm.get_offset(2) + start / 2 * rvstride;
614 let (width, _) = ref_frm.get_dimensions(0);
615 let rdata = ref_frm.get_data();
616
617 let iystride = in_frm.get_stride(0);
618 let mut iyoff = in_frm.get_offset(0) + start * iystride;
619 let iustride = in_frm.get_stride(1);
620 let mut iuoff = in_frm.get_offset(1) + start / 2 * iustride;
621 let ivstride = in_frm.get_stride(2);
622 let mut ivoff = in_frm.get_offset(2) + start / 2 * ivstride;
623 let idata = in_frm.get_data();
624
625 for _ in (start..end).step_by(4) {
626 for x in (0..width).step_by(4) {
627 let mut dist = 0;
628 let mut roff = ryoff + x;
629 let mut ioff = iyoff + x;
630 for _ in 0..4 {
631 for i in 0..4 {
632 let d = i32::from(rdata[roff + i]) - i32::from(idata[ioff + i]);
633 dist += d * d;
634 }
635 roff += rystride;
636 ioff += iystride;
637 }
638 if !self.grayscale {
639 let mut roff = ruoff + x / 2;
640 let mut ioff = iuoff + x / 2;
641 let ud = i32::from(rdata[roff]) - i32::from(idata[ioff]);
642 dist += ud * ud;
643 let ud = i32::from(rdata[roff + 1]) - i32::from(idata[ioff + 1]);
644 dist += ud * ud;
645 roff += rustride; ioff += iustride;
646 let ud = i32::from(rdata[roff]) - i32::from(idata[ioff]);
647 dist += ud * ud;
648 let ud = i32::from(rdata[roff + 1]) - i32::from(idata[ioff + 1]);
649 dist += ud * ud;
650
651 let mut roff = rvoff + x / 2;
652 let mut ioff = ivoff + x / 2;
653 let vd = i32::from(rdata[roff]) - i32::from(idata[ioff]);
654 dist += vd * vd;
655 let vd = i32::from(rdata[roff + 1]) - i32::from(idata[ioff + 1]);
656 dist += vd * vd;
657 roff += rvstride; ioff += ivstride;
658 let vd = i32::from(rdata[roff]) - i32::from(idata[ioff]);
659 dist += vd * vd;
660 let vd = i32::from(rdata[roff + 1]) - i32::from(idata[ioff + 1]);
661 dist += vd * vd;
662 }
663 self.skip_dist.push(dist as u32);
664 }
665
666 iyoff += iystride * 4;
667 iuoff += iustride * 2;
668 ivoff += ivstride * 2;
669 ryoff += rystride * 4;
670 ruoff += rustride * 2;
671 rvoff += rvstride * 2;
672 }
673 } else {
674 unreachable!();
675 }
676 }
3c406629
KS
677 fn quant_vectors(&mut self) {
678 match self.qmode {
679 QuantMode::ELBG => {
7460b53e
KS
680 self.v1_len = elbg_quant(&self.v1_entries, &mut self.v1_cur_cb[self.cur_strip]);
681 self.v4_len = if !self.force_v1 {
682 elbg_quant(&self.v4_entries, &mut self.v4_cur_cb[self.cur_strip])
c6f14420
KS
683 } else {
684 0
685 };
3c406629 686 },
42ef5325
KS
687 QuantMode::Fast => {
688 for bin in self.fst_bins.iter_mut() {
689 bin.clear();
690 }
691 self.v1_len = quant_fast(&mut self.fst_bins, &self.v1_entries, &mut self.v1_cur_cb[self.cur_strip]);
692 self.v4_len = if !self.force_v1 {
693 quant_fast(&mut self.fst_bins, &self.v4_entries, &mut self.v4_cur_cb[self.cur_strip])
694 } else {
695 0
696 };
697 },
3c406629 698 QuantMode::MedianCut => {
9a57fda1 699 self.v1_len = quantise_median_cut::<YUVCode, YUVCodeSum>(&self.v1_entries, &mut self.v1_cur_cb[self.cur_strip]);
c6f14420
KS
700 if !self.force_v1 {
701 self.v4_len = quantise_median_cut::<YUVCode, YUVCodeSum>(&self.v4_entries, &mut self.v4_cur_cb[self.cur_strip]);
702 } else {
703 self.v4_len = 0;
704 }
3c406629
KS
705 },
706 };
592d2889 707
9a57fda1
KS
708 for e in self.v1_cur_cb[self.cur_strip].iter_mut().skip(self.v1_len) { *e = YUVCode::default(); }
709 for e in self.v4_cur_cb[self.cur_strip].iter_mut().skip(self.v4_len) { *e = YUVCode::default(); }
3c406629 710 }
6064de24
KS
711 fn refine_vectors(&mut self) {
712 match self.qmode {
713 QuantMode::ELBG => {
714 self.v1_len = if !self.v1_cand.is_empty() {
715 elbg_quant(&self.v1_cand, &mut self.v1_cur_cb[self.cur_strip])
716 } else {
717 0
718 };
719 self.v4_len = if !self.force_v1 && !self.v4_cand.is_empty() {
720 elbg_quant(&self.v4_cand, &mut self.v4_cur_cb[self.cur_strip])
721 } else {
722 0
723 };
724 },
725 QuantMode::Fast => {
726 for bin in self.fst_bins.iter_mut() {
727 bin.clear();
728 }
729 self.v1_len = if !self.v1_cand.is_empty() {
730 quant_fast(&mut self.fst_bins, &self.v1_cand, &mut self.v1_cur_cb[self.cur_strip])
731 } else {
732 0
733 };
734 self.v4_len = if !self.force_v1 && !self.v4_cand.is_empty() {
735 quant_fast(&mut self.fst_bins, &self.v4_cand, &mut self.v4_cur_cb[self.cur_strip])
736 } else {
737 0
738 };
739 },
740 QuantMode::MedianCut => {
741 self.v1_len = if !self.v1_cand.is_empty() {
742 quantise_median_cut::<YUVCode, YUVCodeSum>(&self.v1_cand, &mut self.v1_cur_cb[self.cur_strip])
743 } else {
744 0
745 };
746 if !self.force_v1 && !self.v4_cand.is_empty() {
747 self.v4_len = quantise_median_cut::<YUVCode, YUVCodeSum>(&self.v4_cand, &mut self.v4_cur_cb[self.cur_strip]);
748 } else {
749 self.v4_len = 0;
750 }
751 },
752 };
753
754 for e in self.v1_cur_cb[self.cur_strip].iter_mut().skip(self.v1_len) { *e = YUVCode::default(); }
755 for e in self.v4_cur_cb[self.cur_strip].iter_mut().skip(self.v4_len) { *e = YUVCode::default(); }
756 }
a178c22c
KS
757 fn encode_intra(&mut self, bw: &mut ByteWriter, in_frm: &NAVideoBuffer<u8>) -> EncoderResult<bool> {
758 let (width, height) = in_frm.get_dimensions(0);
759 let mut strip_h = (height / self.nstrips + 3) & !3;
760 if strip_h == 0 {
761 self.nstrips = 1;
762 strip_h = height;
763 }
764 let mut start_line = 0;
765 let mut end_line = strip_h;
766
767 bw.write_byte(0)?; // intra flag
768 bw.write_u24be(0)?; // frame size
769 let frame_data_pos = bw.tell();
770 bw.write_u16be(width as u16)?;
771 bw.write_u16be(height as u16)?;
772 bw.write_u16be(self.nstrips as u16)?;
773
9a57fda1
KS
774 self.cur_strip = 0;
775 for entry in self.v1_cb[self.cur_strip].iter_mut() {
a178c22c
KS
776 self.rng.fill_entry(entry);
777 }
9a57fda1 778 for entry in self.v4_cb[self.cur_strip].iter_mut() {
a178c22c
KS
779 self.rng.fill_entry(entry);
780 }
781 while start_line < height {
782 self.read_strip(in_frm, start_line, end_line);
783
9a57fda1
KS
784 if self.cur_strip > 0 {
785 self.v1_cb[self.cur_strip] = self.v1_cb[self.cur_strip - 1];
786 self.v4_cb[self.cur_strip] = self.v4_cb[self.cur_strip - 1];
787 }
3c406629 788 self.quant_vectors();
a178c22c 789 if self.grayscale {
9a57fda1 790 for cw in self.v1_cur_cb[self.cur_strip].iter_mut() {
a178c22c
KS
791 cw.u = 128;
792 cw.v = 128;
793 }
9a57fda1 794 for cw in self.v4_cur_cb[self.cur_strip].iter_mut() {
a178c22c
KS
795 cw.u = 128;
796 cw.v = 128;
797 }
798 }
799
37952415
KS
800 self.v1_idx.clear();
801 self.v4_idx.clear();
a178c22c
KS
802 self.masks.reset();
803
6064de24
KS
804 self.cmode.clear();
805 self.v1_cand.clear();
806 self.v4_cand.clear();
a178c22c 807 for (v1_entry, v4_entries) in self.v1_entries.iter().zip(self.v4_entries.chunks(4)) {
9a57fda1 808 let (v1_idx, v1_dist) = Self::find_nearest(&self.v1_cur_cb[self.cur_strip][..self.v1_len], *v1_entry);
c6f14420 809 if v1_dist == 0 || self.force_v1 {
6064de24
KS
810 if !self.refine {
811 self.masks.put_v1();
812 self.v1_idx.push(v1_idx);
813 } else {
814 self.cmode.push(CodingMode::V1);
815 self.v1_cand.push(*v1_entry);
816 }
a178c22c
KS
817 continue;
818 }
9a57fda1
KS
819 let (v40_idx, v40_dist) = Self::find_nearest(&self.v4_cur_cb[self.cur_strip][..self.v4_len], v4_entries[0]);
820 let (v41_idx, v41_dist) = Self::find_nearest(&self.v4_cur_cb[self.cur_strip][..self.v4_len], v4_entries[1]);
821 let (v42_idx, v42_dist) = Self::find_nearest(&self.v4_cur_cb[self.cur_strip][..self.v4_len], v4_entries[2]);
822 let (v43_idx, v43_dist) = Self::find_nearest(&self.v4_cur_cb[self.cur_strip][..self.v4_len], v4_entries[3]);
a178c22c 823 if v40_dist + v41_dist + v42_dist + v43_dist > v1_dist {
6064de24
KS
824 if !self.refine {
825 self.masks.put_v4();
826 self.v4_idx.push(v40_idx);
827 self.v4_idx.push(v41_idx);
828 self.v4_idx.push(v42_idx);
829 self.v4_idx.push(v43_idx);
830 } else {
831 self.cmode.push(CodingMode::V4);
832 self.v4_cand.extend_from_slice(v4_entries);
833 }
a178c22c 834 } else {
6064de24
KS
835 if !self.refine {
836 self.masks.put_v1();
837 self.v1_idx.push(v1_idx);
838 } else {
839 self.cmode.push(CodingMode::V1);
840 self.v1_cand.push(*v1_entry);
841 }
842 }
843 }
844 if self.refine {
845 self.refine_vectors();
846 let mut v1_src = self.v1_cand.iter();
847 let mut v4_src = self.v4_cand.chunks_exact(4);
848 for &cmode in self.cmode.iter() {
849 match cmode {
850 CodingMode::Skip => unreachable!(),
851 CodingMode::V1 => {
852 let v1_entry = v1_src.next().unwrap();
853 let (v1_idx, _) = Self::find_nearest(&self.v1_cur_cb[self.cur_strip][..self.v1_len], *v1_entry);
854 self.masks.put_v1();
855 self.v1_idx.push(v1_idx);
856 },
857 CodingMode::V4 => {
858 let v4_entries = v4_src.next().unwrap();
859 let (v40_idx, _) = Self::find_nearest(&self.v4_cur_cb[self.cur_strip][..self.v4_len], v4_entries[0]);
860 let (v41_idx, _) = Self::find_nearest(&self.v4_cur_cb[self.cur_strip][..self.v4_len], v4_entries[1]);
861 let (v42_idx, _) = Self::find_nearest(&self.v4_cur_cb[self.cur_strip][..self.v4_len], v4_entries[2]);
862 let (v43_idx, _) = Self::find_nearest(&self.v4_cur_cb[self.cur_strip][..self.v4_len], v4_entries[3]);
863
864 self.masks.put_v4();
865 self.v4_idx.push(v40_idx);
866 self.v4_idx.push(v41_idx);
867 self.v4_idx.push(v42_idx);
868 self.v4_idx.push(v43_idx);
869 },
870 };
a178c22c
KS
871 }
872 }
873 self.masks.end();
874
875 let mut is_intra_strip = start_line == 0;
876 let (upd_v1, upd_v4) = if !is_intra_strip {
877 let cb_size = if self.grayscale { 4 } else { 6 };
9f7faaf3
KS
878 (Self::can_update_cb(&self.v1_cur_cb[self.cur_strip][..self.v1_len], &self.v1_cb[self.cur_strip][..self.v1_len], cb_size),
879 Self::can_update_cb(&self.v4_cur_cb[self.cur_strip][..self.v4_len], &self.v4_cb[self.cur_strip][..self.v4_len], cb_size))
a178c22c
KS
880 } else {
881 (false, false)
882 };
883 if !is_intra_strip && !upd_v1 && !upd_v4 {
884 is_intra_strip = true;
885 }
886 bw.write_byte(if is_intra_strip { 0x10 } else { 0x11 })?;
887 bw.write_u24be(0)?; // strip size
888 let strip_data_pos = bw.tell();
889 bw.write_u16be(0)?; // yoff
890 bw.write_u16be(0)?; // xoff
891 bw.write_u16be((end_line - start_line) as u16)?;
892 bw.write_u16be(width as u16)?;
893
9f7faaf3
KS
894 Self::write_cb(bw, 0x20, &self.v4_cur_cb[self.cur_strip], &self.v4_cb[self.cur_strip], self.grayscale, upd_v4, self.v4_len)?;
895 Self::write_cb(bw, 0x22, &self.v1_cur_cb[self.cur_strip], &self.v1_cb[self.cur_strip], self.grayscale, upd_v1, self.v1_len)?;
a178c22c
KS
896
897 self.render_stripe(true, start_line, end_line);
898
61cab15b 899 if self.v4_idx.is_empty() {
a178c22c 900 bw.write_byte(0x32)?;
1047e983
KS
901 bw.write_u24be((self.v1_idx.len() + 4) as u32)?;
902 bw.write_buf(self.v1_idx.as_slice())?;
a178c22c
KS
903 } else {
904 bw.write_byte(0x30)?;
905 bw.write_u24be(0)?;
906 let chunk_pos = bw.tell();
907 let mut v1_pos = 0;
908 let mut v4_pos = 0;
909 for _ in 0..32 {
910 self.v1_idx.push(0);
911 self.v4_idx.push(0);
912 self.v4_idx.push(0);
913 self.v4_idx.push(0);
914 self.v4_idx.push(0);
915 }
916 for mask in self.masks.masks.iter() {
917 bw.write_u32be(*mask)?;
918 for j in (0..32).rev() {
919 if (mask & (1 << j)) == 0 {
920 bw.write_byte(self.v1_idx[v1_pos])?;
921 v1_pos += 1;
922 } else {
923 bw.write_byte(self.v4_idx[v4_pos])?;
924 bw.write_byte(self.v4_idx[v4_pos + 1])?;
925 bw.write_byte(self.v4_idx[v4_pos + 2])?;
926 bw.write_byte(self.v4_idx[v4_pos + 3])?;
927 v4_pos += 4;
928 }
929 }
930 }
931 patch_size(bw, chunk_pos)?;
932 }
933
934 patch_size(bw, strip_data_pos)?;
935
9a57fda1
KS
936 self.v1_cb[self.cur_strip].copy_from_slice(&self.v1_cur_cb[self.cur_strip]);
937 self.v4_cb[self.cur_strip].copy_from_slice(&self.v4_cur_cb[self.cur_strip]);
a178c22c
KS
938 start_line = end_line;
939 end_line = (end_line + strip_h).min(height);
9a57fda1
KS
940
941 self.cur_strip += 1;
a178c22c
KS
942 }
943 patch_size(bw, frame_data_pos)?;
944 Ok(true)
945 }
946 fn encode_inter(&mut self, bw: &mut ByteWriter, in_frm: &NAVideoBuffer<u8>) -> EncoderResult<bool> {
947 let (width, height) = in_frm.get_dimensions(0);
948 let mut strip_h = (height / self.nstrips + 3) & !3;
949 if strip_h == 0 {
950 self.nstrips = 1;
951 strip_h = height;
952 }
953 let mut start_line = 0;
954 let mut end_line = strip_h;
955
956 bw.write_byte(1)?; // intra flag
957 bw.write_u24be(0)?; // frame size
958 let frame_data_pos = bw.tell();
959 bw.write_u16be(width as u16)?;
960 bw.write_u16be(height as u16)?;
961 bw.write_u16be(self.nstrips as u16)?;
962
9a57fda1 963 self.cur_strip = 0;
a178c22c
KS
964 while start_line < height {
965 self.read_strip(in_frm, start_line, end_line);
966 self.calc_skip_dist(in_frm, start_line, end_line);
967
3c406629 968 self.quant_vectors();
a178c22c 969 if self.grayscale {
9a57fda1 970 for cw in self.v1_cur_cb[self.cur_strip].iter_mut() {
a178c22c
KS
971 cw.u = 128;
972 cw.v = 128;
973 }
9a57fda1 974 for cw in self.v4_cur_cb[self.cur_strip].iter_mut() {
a178c22c
KS
975 cw.u = 128;
976 cw.v = 128;
977 }
978 }
979
37952415
KS
980 self.v1_idx.clear();
981 self.v4_idx.clear();
a178c22c
KS
982 self.masks.reset();
983
6064de24
KS
984 self.cmode.clear();
985 self.v1_cand.clear();
986 self.v4_cand.clear();
987
a178c22c
KS
988 let mut skip_iter = self.skip_dist.iter();
989 for (v1_entry, v4_entries) in self.v1_entries.iter().zip(self.v4_entries.chunks(4)) {
990 let skip_dist = *skip_iter.next().unwrap();
991 if skip_dist == 0 {
6064de24
KS
992 if !self.refine {
993 self.masks.put_inter(true);
994 } else {
995 self.cmode.push(CodingMode::Skip);
996 }
a178c22c
KS
997 continue;
998 }
9a57fda1 999 let (v1_idx, v1_dist) = Self::find_nearest(&self.v1_cur_cb[self.cur_strip][..self.v1_len], *v1_entry);
a178c22c 1000 if skip_dist < v1_dist {
6064de24
KS
1001 if !self.refine {
1002 self.masks.put_inter(true);
1003 } else {
1004 self.cmode.push(CodingMode::Skip);
1005 }
a178c22c 1006 continue;
6064de24 1007 } else if !self.refine {
a178c22c
KS
1008 self.masks.put_inter(false);
1009 }
c6f14420 1010 if v1_dist == 0 || self.force_v1 {
6064de24
KS
1011 if !self.refine {
1012 self.masks.put_v1();
1013 self.v1_idx.push(v1_idx);
1014 } else {
1015 self.cmode.push(CodingMode::V1);
1016 self.v1_cand.push(*v1_entry);
1017 }
a178c22c
KS
1018 continue;
1019 }
9a57fda1
KS
1020 let (v40_idx, v40_dist) = Self::find_nearest(&self.v4_cur_cb[self.cur_strip][..self.v4_len], v4_entries[0]);
1021 let (v41_idx, v41_dist) = Self::find_nearest(&self.v4_cur_cb[self.cur_strip][..self.v4_len], v4_entries[1]);
1022 let (v42_idx, v42_dist) = Self::find_nearest(&self.v4_cur_cb[self.cur_strip][..self.v4_len], v4_entries[2]);
1023 let (v43_idx, v43_dist) = Self::find_nearest(&self.v4_cur_cb[self.cur_strip][..self.v4_len], v4_entries[3]);
a178c22c 1024 if v40_dist + v41_dist + v42_dist + v43_dist > v1_dist {
6064de24
KS
1025 if !self.refine {
1026 self.masks.put_v4();
1027 self.v4_idx.push(v40_idx);
1028 self.v4_idx.push(v41_idx);
1029 self.v4_idx.push(v42_idx);
1030 self.v4_idx.push(v43_idx);
1031 } else {
1032 self.cmode.push(CodingMode::V4);
1033 self.v4_cand.extend_from_slice(v4_entries);
1034 }
a178c22c 1035 } else {
6064de24
KS
1036 if !self.refine {
1037 self.masks.put_v1();
1038 self.v1_idx.push(v1_idx);
1039 } else {
1040 self.cmode.push(CodingMode::V1);
1041 self.v1_cand.push(*v1_entry);
1042 }
1043 }
1044 }
1045 if self.refine {
1046 self.refine_vectors();
1047 let mut v1_src = self.v1_cand.iter();
1048 let mut v4_src = self.v4_cand.chunks_exact(4);
1049 for &cmode in self.cmode.iter() {
1050 match cmode {
1051 CodingMode::Skip => {
1052 self.masks.put_inter(true);
1053 },
1054 CodingMode::V1 => {
1055 let v1_entry = v1_src.next().unwrap();
1056 let (v1_idx, _) = Self::find_nearest(&self.v1_cur_cb[self.cur_strip][..self.v1_len], *v1_entry);
1057 self.masks.put_inter(false);
1058 self.masks.put_v1();
1059 self.v1_idx.push(v1_idx);
1060 },
1061 CodingMode::V4 => {
1062 let v4_entries = v4_src.next().unwrap();
1063 let (v40_idx, _) = Self::find_nearest(&self.v4_cur_cb[self.cur_strip][..self.v4_len], v4_entries[0]);
1064 let (v41_idx, _) = Self::find_nearest(&self.v4_cur_cb[self.cur_strip][..self.v4_len], v4_entries[1]);
1065 let (v42_idx, _) = Self::find_nearest(&self.v4_cur_cb[self.cur_strip][..self.v4_len], v4_entries[2]);
1066 let (v43_idx, _) = Self::find_nearest(&self.v4_cur_cb[self.cur_strip][..self.v4_len], v4_entries[3]);
1067
1068 self.masks.put_inter(false);
1069 self.masks.put_v4();
1070 self.v4_idx.push(v40_idx);
1071 self.v4_idx.push(v41_idx);
1072 self.v4_idx.push(v42_idx);
1073 self.v4_idx.push(v43_idx);
1074 },
1075 };
a178c22c
KS
1076 }
1077 }
1078 self.masks.end();
1079
1080 let (upd_v1, upd_v4) = {
1081 let cb_size = if self.grayscale { 4 } else { 6 };
9f7faaf3
KS
1082 (Self::can_update_cb(&self.v1_cur_cb[self.cur_strip][..self.v1_len], &self.v1_cb[self.cur_strip][..self.v1_len], cb_size),
1083 Self::can_update_cb(&self.v4_cur_cb[self.cur_strip][..self.v4_len], &self.v4_cb[self.cur_strip][..self.v4_len], cb_size))
a178c22c
KS
1084 };
1085 bw.write_byte(0x11)?;
1086 bw.write_u24be(0)?; // strip size
1087 let strip_data_pos = bw.tell();
1088 bw.write_u16be(0)?; // yoff
1089 bw.write_u16be(0)?; // xoff
1090 bw.write_u16be((end_line - start_line) as u16)?;
1091 bw.write_u16be(width as u16)?;
1092
9f7faaf3
KS
1093 Self::write_cb(bw, 0x20, &self.v4_cur_cb[self.cur_strip], &self.v4_cb[self.cur_strip], self.grayscale, upd_v4, self.v4_len)?;
1094 Self::write_cb(bw, 0x22, &self.v1_cur_cb[self.cur_strip], &self.v1_cb[self.cur_strip], self.grayscale, upd_v1, self.v1_len)?;
a178c22c
KS
1095
1096 self.render_stripe(false, start_line, end_line);
1097
1098 bw.write_byte(0x31)?;
1099 bw.write_u24be(0)?;
1100 let chunk_pos = bw.tell();
1101 let mut v1_pos = 0;
1102 let mut v4_pos = 0;
1103 for _ in 0..32 {
1104 self.v1_idx.push(0);
1105 self.v4_idx.push(0);
1106 self.v4_idx.push(0);
1107 self.v4_idx.push(0);
1108 self.v4_idx.push(0);
1109 }
1110 let mut skip = true;
1111 for mask in self.masks.masks.iter() {
1112 bw.write_u32be(*mask)?;
10dedf0d 1113 if *mask == 0 && skip { continue; }
a178c22c
KS
1114 let mut bit = 1 << 31;
1115 while bit > 0 {
1116 if skip {
1117 skip = (mask & bit) == 0;
1118 bit >>= 1;
1119 } else {
1120 if (mask & bit) == 0 {
1121 bw.write_byte(self.v1_idx[v1_pos])?;
1122 v1_pos += 1;
1123 } else {
1124 bw.write_byte(self.v4_idx[v4_pos])?;
1125 bw.write_byte(self.v4_idx[v4_pos + 1])?;
1126 bw.write_byte(self.v4_idx[v4_pos + 2])?;
1127 bw.write_byte(self.v4_idx[v4_pos + 3])?;
1128 v4_pos += 4;
1129 }
1130 bit >>= 1;
1131 skip = true;
1132 }
1133 }
1134 }
1135 patch_size(bw, chunk_pos)?;
1136
1137 patch_size(bw, strip_data_pos)?;
1138
9a57fda1
KS
1139 self.v1_cb[self.cur_strip].copy_from_slice(&self.v1_cur_cb[self.cur_strip]);
1140 self.v4_cb[self.cur_strip].copy_from_slice(&self.v4_cur_cb[self.cur_strip]);
a178c22c
KS
1141 start_line = end_line;
1142 end_line = (end_line + strip_h).min(height);
9a57fda1
KS
1143
1144 self.cur_strip += 1;
a178c22c
KS
1145 }
1146 patch_size(bw, frame_data_pos)?;
1147 Ok(true)
1148 }
1149}
1150
1151impl NAEncoder for CinepakEncoder {
1152 fn negotiate_format(&self, encinfo: &EncodeParameters) -> EncoderResult<EncodeParameters> {
1153 match encinfo.format {
1154 NACodecTypeInfo::None => {
6f263099
KS
1155 Ok(EncodeParameters {
1156 format: NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, true, YUV420_FORMAT)),
1157 ..Default::default()
1158 })
a178c22c 1159 },
61cab15b 1160 NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
a178c22c
KS
1161 NACodecTypeInfo::Video(vinfo) => {
1162 let pix_fmt = if vinfo.format == GRAY_FORMAT { GRAY_FORMAT } else { YUV420_FORMAT };
4abaf99e 1163 let outinfo = NAVideoInfo::new((vinfo.width + 3) & !3, (vinfo.height + 3) & !3, false, pix_fmt);
d722ffe9 1164 let mut ofmt = *encinfo;
a178c22c
KS
1165 ofmt.format = NACodecTypeInfo::Video(outinfo);
1166 Ok(ofmt)
1167 }
1168 }
1169 }
2757a028 1170 fn get_capabilities(&self) -> u64 { 0 }
a178c22c
KS
1171 fn init(&mut self, stream_id: u32, encinfo: EncodeParameters) -> EncoderResult<NAStreamRef> {
1172 match encinfo.format {
1173 NACodecTypeInfo::None => Err(EncoderError::FormatError),
1174 NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
1175 NACodecTypeInfo::Video(vinfo) => {
1176 if vinfo.format != YUV420_FORMAT && vinfo.format != GRAY_FORMAT {
1177 return Err(EncoderError::FormatError);
1178 }
1179 if ((vinfo.width | vinfo.height) & 3) != 0 {
1180 return Err(EncoderError::FormatError);
1181 }
1182 if (vinfo.width | vinfo.height) >= (1 << 16) {
1183 return Err(EncoderError::FormatError);
1184 }
1185
1186 let out_info = NAVideoInfo::new(vinfo.width, vinfo.height, false, vinfo.format);
61cab15b 1187 let info = NACodecInfo::new("cinepak", NACodecTypeInfo::Video(out_info), None);
a480a0de 1188 let mut stream = NAStream::new(StreamType::Video, stream_id, info, encinfo.tb_num, encinfo.tb_den, 0);
2ff56201
KS
1189 stream.set_num(stream_id as usize);
1190 let stream = stream.into_ref();
a178c22c
KS
1191
1192 self.stream = Some(stream.clone());
1193 self.quality = encinfo.quality;
1194 self.grayscale = vinfo.format != YUV420_FORMAT;
1195 let num_blocks = vinfo.width / 2 * vinfo.height / 2;
1196 self.v1_entries = Vec::with_capacity(num_blocks);
1197 self.v4_entries = Vec::with_capacity(num_blocks * 4);
1198 self.v1_idx = Vec::with_capacity(num_blocks);
1199 self.v4_idx = Vec::with_capacity(num_blocks * 4);
1200 self.skip_dist = Vec::with_capacity(vinfo.width / 4 * vinfo.height / 4);
1201
1202 let buf = alloc_video_buffer(out_info, 2)?;
1203 self.lastfrm = Some(buf.get_vbuf().unwrap());
c8db9313 1204
a178c22c
KS
1205 Ok(stream)
1206 },
1207 }
1208 }
1209 fn encode(&mut self, frm: &NAFrame) -> EncoderResult<()> {
1210 let buf = frm.get_buffer();
1211 if let Some(ref vbuf) = buf.get_vbuf() {
8c3f822a
KS
1212 if self.nstrips == 0 {
1213 let (w, h) = vbuf.get_dimensions(0);
1214 self.nstrips = ((((w * h) >> 4) + 1200) / 2400).max(1).min(3);
1215 let strip_h = ((h + self.nstrips - 1) / self.nstrips + 3) & !3;
1216 self.nstrips = (h + strip_h - 1) / strip_h;
1217 }
9a57fda1
KS
1218 let cur_strips = self.v1_cb.len();
1219 if cur_strips != self.nstrips {
1220 self.frmcount = 0;
1221 }
1222 if cur_strips < self.nstrips {
1223 for _ in cur_strips..self.nstrips {
1224 self.v1_cb.push([YUVCode::default(); 256]);
1225 self.v4_cb.push([YUVCode::default(); 256]);
1226 self.v1_cur_cb.push([YUVCode::default(); 256]);
1227 self.v4_cur_cb.push([YUVCode::default(); 256]);
1228 }
1229 }
1230
a178c22c
KS
1231 let mut dbuf = Vec::with_capacity(4);
1232 let mut gw = GrowableMemoryWriter::new_write(&mut dbuf);
1233 let mut bw = ByteWriter::new(&mut gw);
1234 let is_intra = if self.frmcount == 0 {
1235 self.encode_intra(&mut bw, vbuf)?
1236 } else {
1237 self.encode_inter(&mut bw, vbuf)?
1238 };
1239 self.pkt = Some(NAPacket::new(self.stream.clone().unwrap(), frm.ts, is_intra, dbuf));
1240 self.frmcount += 1;
3c406629 1241 if self.frmcount == self.key_int {
a178c22c
KS
1242 self.frmcount = 0;
1243 }
1244 Ok(())
1245 } else {
1246 Err(EncoderError::InvalidParameters)
1247 }
1248 }
1249 fn get_packet(&mut self) -> EncoderResult<Option<NAPacket>> {
1250 let mut npkt = None;
1251 std::mem::swap(&mut self.pkt, &mut npkt);
1252 Ok(npkt)
1253 }
1254 fn flush(&mut self) -> EncoderResult<()> {
1255 self.frmcount = 0;
1256 Ok(())
1257 }
1258}
1259
3c406629
KS
1260const ENCODER_OPTS: &[NAOptionDefinition] = &[
1261 NAOptionDefinition {
ee0ca773 1262 name: KEYFRAME_OPTION, description: KEYFRAME_OPTION_DESC,
3c406629
KS
1263 opt_type: NAOptionDefinitionType::Int(Some(0), Some(128)) },
1264 NAOptionDefinition {
1265 name: "nstrips", description: "Number of strips per frame (0 - automatic)",
1266 opt_type: NAOptionDefinitionType::Int(Some(0), Some(16)) },
1267 NAOptionDefinition {
1268 name: "quant_mode", description: "Quantisation mode",
42ef5325 1269 opt_type: NAOptionDefinitionType::String(Some(&["elbg", "fast", "mediancut"])) },
c6f14420
KS
1270 NAOptionDefinition {
1271 name: "force_v1", description: "Force coarse (V1-only) mode",
1272 opt_type: NAOptionDefinitionType::Bool },
6064de24
KS
1273 NAOptionDefinition {
1274 name: "refine", description: "Try to improve coded picture",
1275 opt_type: NAOptionDefinitionType::Bool },
3c406629
KS
1276];
1277
a178c22c 1278impl NAOptionHandler for CinepakEncoder {
3c406629
KS
1279 fn get_supported_options(&self) -> &[NAOptionDefinition] { ENCODER_OPTS }
1280 fn set_options(&mut self, options: &[NAOption]) {
1281 for option in options.iter() {
3c406629
KS
1282 for opt_def in ENCODER_OPTS.iter() {
1283 if opt_def.check(option).is_ok() {
1284 match option.name {
ee0ca773 1285 KEYFRAME_OPTION => {
3c406629
KS
1286 if let NAValue::Int(intval) = option.value {
1287 self.key_int = intval as u8;
1288 }
1289 },
1290 "nstrips" => {
1291 if let NAValue::Int(intval) = option.value {
1292 self.nstrips = intval as usize;
1293 }
1294 },
1295 "quant_mode" => {
405cec9e
KS
1296 if let NAValue::String(ref strval) = option.value {
1297 match strval.as_str() {
3c406629 1298 "elbg" => self.qmode = QuantMode::ELBG,
42ef5325 1299 "fast" => self.qmode = QuantMode::Fast,
3c406629
KS
1300 "mediancut" => self.qmode = QuantMode::MedianCut,
1301 _ => {},
1302 };
1303 }
1304 },
c6f14420
KS
1305 "force_v1" => {
1306 if let NAValue::Bool(val) = option.value {
1307 self.force_v1 = val;
1308 }
1309 },
6064de24
KS
1310 "refine" => {
1311 if let NAValue::Bool(val) = option.value {
1312 self.refine = val;
1313 }
1314 },
3c406629
KS
1315 _ => {},
1316 };
1317 }
1318 }
1319 }
1320 }
1321 fn query_option_value(&self, name: &str) -> Option<NAValue> {
1322 match name {
8211e0aa 1323 KEYFRAME_OPTION => Some(NAValue::Int(i64::from(self.key_int))),
3c406629
KS
1324 "nstrips" => Some(NAValue::Int(self.nstrips as i64)),
1325 "quant_mode" => Some(NAValue::String(self.qmode.to_string())),
c6f14420 1326 "force_v1" => Some(NAValue::Bool(self.force_v1)),
6064de24 1327 "refine" => Some(NAValue::Bool(self.refine)),
3c406629
KS
1328 _ => None,
1329 }
1330 }
a178c22c
KS
1331}
1332
1333pub fn get_encoder() -> Box<dyn NAEncoder + Send> {
1334 Box::new(CinepakEncoder::new())
1335}
1336
1337#[cfg(test)]
1338mod test {
1339 use nihav_core::codecs::*;
1340 use nihav_core::demuxers::*;
1341 use nihav_core::muxers::*;
1342 use crate::*;
1343 use nihav_codec_support::test::enc_video::*;
1344
1345 #[test]
1346 fn test_cinepak_encoder() {
1347 let mut dmx_reg = RegisteredDemuxers::new();
1348 generic_register_all_demuxers(&mut dmx_reg);
1349 let mut dec_reg = RegisteredDecoders::new();
78fb6560 1350 generic_register_all_decoders(&mut dec_reg);
a178c22c
KS
1351 let mut mux_reg = RegisteredMuxers::new();
1352 generic_register_all_muxers(&mut mux_reg);
1353 let mut enc_reg = RegisteredEncoders::new();
1354 generic_register_all_encoders(&mut enc_reg);
1355
886cde48 1356 // sample: https://samples.mplayerhq.hu/V-codecs/UCOD/TalkingHead_352x288.avi
a178c22c
KS
1357 let dec_config = DecoderTestParams {
1358 demuxer: "avi",
1359 in_name: "assets/Misc/TalkingHead_352x288.avi",
1360 stream_type: StreamType::Video,
1361 limit: Some(2),
1362 dmx_reg, dec_reg,
1363 };
1364 let enc_config = EncoderTestParams {
1365 muxer: "avi",
1366 enc_name: "cinepak",
1367 out_name: "cinepak.avi",
1368 mux_reg, enc_reg,
1369 };
1370 let dst_vinfo = NAVideoInfo {
1371 width: 0,
1372 height: 0,
1373 format: YUV420_FORMAT,
1374 flipped: true,
6bc499a0 1375 bits: 12,
a178c22c
KS
1376 };
1377 let enc_params = EncodeParameters {
1378 format: NACodecTypeInfo::Video(dst_vinfo),
1379 quality: 0,
1380 bitrate: 0,
1381 tb_num: 0,
1382 tb_den: 0,
1383 flags: 0,
1384 };
42ef5325
KS
1385 let enc_options = &[
1386 NAOption { name: "quant_mode", value: NAValue::String("mediancut".to_string()) },
1387 ];
1388 //test_encoding_to_file(&dec_config, &enc_config, enc_params, enc_options);
1389 test_encoding_md5(&dec_config, &enc_config, enc_params, enc_options,
9f7faaf3 1390 &[0x1d4690c8, 0x3b15b4b3, 0xc2df3c7b, 0x1a25b159]);
a178c22c
KS
1391 }
1392}