fix clippy warnings
[nihav.git] / nihav-ms / src / codecs / msvideo1enc.rs
CommitLineData
dab59886
KS
1use nihav_core::codecs::*;
2use nihav_core::io::byteio::*;
dab59886 3
adfa9ca4
KS
4type UnpackedPixel = [u16; 4];
5
608a923f
KS
6fn map_quality_pal(quality: u8) -> (u32, u32) {
7 if quality == 0 {
8 (0, 0)
9 } else {
10 let skip_threshold = (10 - (u32::from(quality) / 10).min(10)) * (8 << 6);
11 let fill_threshold = (10 - (u32::from(quality) / 10).min(10)) * (16 << 6);
12 (skip_threshold, fill_threshold)
13 }
14}
15
16fn map_quality_15bit(quality: u8) -> (u32, u32) {
b55da0ef
KS
17 if quality == 0 {
18 (0, 0)
19 } else {
20 let skip_threshold = (10 - (u32::from(quality) / 10).min(10)) * 8;
21 let fill_threshold = (10 - (u32::from(quality) / 10).min(10)) * 16;
22 (skip_threshold, fill_threshold)
23 }
24}
25
81d5776a 26trait PixelOps {
adfa9ca4 27 fn unpack(&self) -> UnpackedPixel;
81d5776a
KS
28 fn dist<T: PixelOps>(&self, val: T) -> u32 {
29 dist_core(self.unpack(), &val.unpack())
dab59886 30 }
81d5776a
KS
31}
32
33impl PixelOps for u16 {
adfa9ca4 34 fn unpack(&self) -> UnpackedPixel {
81d5776a
KS
35 let val = *self;
36 let r = (val >> 10) & 0x1F;
37 let g = (val >> 5) & 0x1F;
38 let b = val & 0x1F;
39 [r, g, b, rgb2y(r, g, b)]
dab59886 40 }
81d5776a
KS
41}
42
adfa9ca4 43fn dist_core(val: UnpackedPixel, other: &UnpackedPixel) -> u32 {
81d5776a
KS
44 let sum = val.iter().zip(other.iter()).take(3).fold(0i32,
45 |acc, (&a, &b)| {
46 let diff = i32::from(a) - i32::from(b);
47 acc + diff * diff
48 });
49 sum as u32
50}
51
608a923f
KS
52fn find_nearest(pix: UnpackedPixel, pal: &[UnpackedPixel; 256]) -> usize {
53 let mut bestidx = 0;
54 let mut bestdist = std::u32::MAX;
55
56 for (idx, entry) in pal.iter().enumerate() {
57 let dist = dist_core(pix, entry);
58 if dist == 0 {
59 return idx;
60 }
61 if bestdist > dist {
62 bestdist = dist;
63 bestidx = idx;
64 }
65 }
66 bestidx
67}
68
69struct LocalSearch {
70 pal: [UnpackedPixel; 256],
71 db: Vec<Vec<UnpackedPixel>>,
72}
73
74impl LocalSearch {
75 fn quant(key: UnpackedPixel) -> usize {
76 (((key[0] >> 3) as usize) << 10) |
77 (((key[1] >> 3) as usize) << 5) |
78 ((key[2] >> 3) as usize)
79 }
80 fn new() -> Self {
81 let mut db = Vec::with_capacity(1 << 15);
82 for _ in 0..(1 << 15) {
83 db.push(Vec::new());
84 }
85 Self {
86 pal: [UnpackedPixel::default(); 256],
87 db
88 }
89 }
90 fn recalculate(&mut self, pal: &[UnpackedPixel; 256]) {
91 self.pal = *pal;
92 for vec in self.db.iter_mut() {
93 vec.clear();
94 }
95 for (i, palentry) in pal.iter().enumerate() {
96 let r0 = (palentry[0] >> 3) as usize;
97 let g0 = (palentry[1] >> 3) as usize;
98 let b0 = (palentry[2] >> 3) as usize;
99 for r in r0.saturating_sub(1)..=(r0 + 1).min(31) {
100 for g in g0.saturating_sub(1)..=(g0 + 1).min(31) {
101 for b in b0.saturating_sub(1)..=(b0 + 1).min(31) {
102 let idx = (r << 10) | (g << 5) | b;
103 self.db[idx].push([palentry[0], palentry[1], palentry[2], i as u16]);
104 }
105 }
106 }
107 }
108 }
109 fn search(&self, pix: UnpackedPixel) -> usize {
110 let idx = Self::quant(pix);
111 let mut best_dist = std::u32::MAX;
112 let mut best_idx = 0;
113 let mut count = 0;
114 for clr in self.db[idx].iter() {
115 let dist = dist_core(pix, clr);
116 count += 1;
117 if best_dist > dist {
118 best_dist = dist;
119 best_idx = clr[3] as usize;
120 if dist == 0 { break; }
121 }
122 }
123 if count > 0 {
124 best_idx
125 } else {
126 find_nearest(pix, &self.pal)
127 }
128 }
129}
81d5776a
KS
130
131fn rgb2y(r: u16, g: u16, b: u16) -> u16 {
132 (r * 77 + g * 150 + b * 29) >> 8
133}
134
adfa9ca4 135fn pack_rgb555(val: UnpackedPixel) -> u16 {
81d5776a
KS
136 (val[0] << 10) | (val[1] << 5) | val[2]
137}
138
139#[derive(Default)]
140struct PixelAverage {
adfa9ca4 141 sum: UnpackedPixel,
81d5776a
KS
142 count: u16,
143}
144
145impl PixelAverage {
146 fn new() -> Self { Self::default() }
adfa9ca4 147 fn add(&mut self, val: &UnpackedPixel) {
81d5776a
KS
148 for (dst, &src) in self.sum.iter_mut().zip(val.iter()) {
149 *dst += src;
dab59886 150 }
81d5776a 151 self.count += 1;
dab59886 152 }
adfa9ca4 153 fn get_avg(&self) -> UnpackedPixel {
81d5776a
KS
154 if self.count > 0 {
155 let mut ret = self.sum;
156 for el in ret.iter_mut() {
157 *el /= self.count;
158 }
159 ret
dab59886 160 } else {
81d5776a 161 [0; 4]
dab59886
KS
162 }
163 }
164}
165
81d5776a
KS
166macro_rules! quant_template {
167 ($name:ident, $N:expr) => {
adfa9ca4 168 fn $name(pix: &[UnpackedPixel; $N]) -> ([UnpackedPixel; 2], u16, u32) {
81d5776a
KS
169 let mut avg = PixelAverage::new();
170 let mut maxv = [0; 4];
171 let mut minv = [255; 4];
adfa9ca4
KS
172 for src in pix.iter() {
173 avg.add(src);
174 for ((maxv, minv), &comp) in maxv.iter_mut().zip(minv.iter_mut()).zip(src.iter()) {
81d5776a
KS
175 *maxv = (*maxv).max(comp);
176 *minv = (*minv).min(comp);
177 }
178 }
179 let avg = avg.get_avg();
dab59886 180
81d5776a
KS
181 let mut best_axis = 3;
182 let mut best_dist = maxv[3] - minv[3];
183 for (comp_no, (&minval, &maxval)) in minv.iter().zip(maxv.iter()).enumerate().take(3) {
184 if maxval - minval > best_dist {
185 best_axis = comp_no;
186 best_dist = maxval - minval;
187 }
188 }
189 if best_dist == 0 {
81d5776a 190 let mut dist = 0;
adfa9ca4 191 for el in pix.iter() {
81d5776a
KS
192 dist += dist_core(avg, el);
193 }
adfa9ca4 194 return ([avg; 2], 0, dist);
81d5776a
KS
195 }
196
197 let mut avg1 = PixelAverage::new();
198 let mut avg2 = PixelAverage::new();
199 let mut mask = 0;
200 let mut mask_bit = 1;
adfa9ca4 201 for clr in pix.iter() {
81d5776a
KS
202 if clr[best_axis] > avg[best_axis] {
203 avg2.add(clr);
81d5776a
KS
204 } else {
205 avg1.add(clr);
2bf1f233 206 mask |= mask_bit;
81d5776a
KS
207 }
208 mask_bit <<= 1;
209 }
210
211 let clr0 = avg1.get_avg();
212 let clr1 = avg2.get_avg();
213 let mut dist = 0;
adfa9ca4 214 for clr in pix.iter() {
81d5776a
KS
215 let dist0 = dist_core(clr0, clr);
216 let dist1 = dist_core(clr1, clr);
217 dist += dist0.min(dist1);
218 }
adfa9ca4 219 ([clr0, clr1], mask, dist)
dab59886
KS
220 }
221 }
222}
223
81d5776a
KS
224quant_template!(quant2_16pix, 16);
225quant_template!(quant2_4pix, 4);
226
dab59886
KS
227#[derive(Default)]
228struct BlockState {
229 fill_dist: u32,
adfa9ca4 230 fill_val: UnpackedPixel,
dab59886
KS
231 clr2_dist: u32,
232 clr2_flags: u16,
adfa9ca4 233 clr2: [UnpackedPixel; 2],
dab59886
KS
234 clr8_dist: u32,
235 clr8_flags: u16,
adfa9ca4
KS
236 clr8: [[UnpackedPixel; 2]; 4],
237 pal_mode: bool,
dab59886
KS
238}
239
240impl BlockState {
608a923f 241 fn new_pal() -> Self { Self { pal_mode: true, ..Default::default() } }
adfa9ca4
KS
242 fn set_fill_val(&mut self, val: UnpackedPixel) {
243 self.fill_val = val;
244 if !self.pal_mode {
245 self.fill_val[0] &= !1;
246 }
247 }
248 fn calc_clrs(buf: &[UnpackedPixel; 16]) -> (Option<UnpackedPixel>, Option<UnpackedPixel>) {
93d1e373 249 let clr0 = buf[0];
adfa9ca4
KS
250 let mut clr1 = clr0;
251 let mut single = true;
93d1e373 252 for &pix in buf[1..].iter() {
adfa9ca4
KS
253 if pix != clr0 {
254 if single {
93d1e373 255 clr1 = pix;
adfa9ca4
KS
256 single = false;
257 } else if pix != clr1 {
258 return (None, None);
93d1e373
KS
259 }
260 }
261 }
adfa9ca4
KS
262 if !single {
263 (Some(clr0), Some(clr1))
264 } else {
265 (Some(clr0), None)
266 }
93d1e373 267 }
adfa9ca4 268 fn calc_stats(&mut self, buf: &[UnpackedPixel; 16]) {
93d1e373
KS
269 let mut filled = false;
270 let mut two_clr = false;
adfa9ca4
KS
271 match Self::calc_clrs(buf) {
272 (Some(clr0), Some(clr1)) => {
273 self.clr2[0] = clr0;
274 self.clr2[1] = clr1;
275 two_clr = true;
276 },
277 (Some(clr0), None) => {
278 self.clr2[0] = clr0;
279 self.clr2[1] = clr0;
280 self.set_fill_val(buf[0]);
93d1e373 281 filled = true;
adfa9ca4
KS
282 two_clr = true;
283 },
284 _ => {},
285 };
93d1e373
KS
286 self.fill_dist = 0;
287 if !filled {
81d5776a 288 let mut avg = PixelAverage::new();
adfa9ca4
KS
289 for pix in buf.iter() {
290 avg.add(pix);
dab59886 291 }
adfa9ca4 292 self.set_fill_val(avg.get_avg());
93d1e373 293 for pix in buf.iter() {
adfa9ca4 294 self.fill_dist += dist_core(self.fill_val, pix);
93d1e373 295 }
dab59886
KS
296 }
297 if self.fill_dist == 0 {
298 self.clr2_dist = std::u32::MAX;
299 self.clr8_dist = std::u32::MAX;
300 return;
301 }
302
303 self.clr2_flags = 0u16;
93d1e373
KS
304 if two_clr {
305 let mut mask = 1;
306 self.clr2_dist = 0;
307 for &pix in buf.iter() {
308 if pix == self.clr2[0] {
309 self.clr2_flags |= mask;
310 } else {
311 }
312 mask <<= 1;
313 }
314 if (self.clr2_flags & 0x8000) != 0 {
315 self.clr2_flags = !self.clr2_flags;
316 self.clr2.swap(0, 1);
317 }
81d5776a 318 } else {
e6aaad5c 319 let (clrs, mask, dist) = quant2_16pix(buf);
81d5776a
KS
320 self.clr2 = clrs;
321 self.clr2_flags = mask;
322 self.clr2_dist = dist;
dab59886
KS
323 if (self.clr2_flags & 0x8000) != 0 {
324 self.clr2_flags = !self.clr2_flags;
325 self.clr2.swap(0, 1);
326 }
dab59886
KS
327 }
328 if self.clr2_dist == 0 {
329 self.clr8_dist = std::u32::MAX;
330 return;
331 }
332
adfa9ca4 333 self.clr8 = [[UnpackedPixel::default(); 2]; 4];
dab59886
KS
334 self.clr8_flags = 0;
335 self.clr8_dist = 0;
dab59886
KS
336 for i in 0..4 {
337 let off = (i & 1) * 2 + (i & 2) * 4;
338 let src2 = [buf[off], buf[off + 1], buf[off + 4], buf[off + 5]];
81d5776a
KS
339 let (clrs, mask, dist) = quant2_4pix(&src2);
340 self.clr8[i] = clrs;
2bf1f233
KS
341 let lo_bits = mask & 0x3;
342 let hi_bits = (mask & 0xC) << 2;
b4c5fc31 343 self.clr8_flags |= (hi_bits | lo_bits) << ((i & 1) * 2 + (i & 2) * 4);
81d5776a 344 self.clr8_dist += dist;
dab59886 345 }
dab59886 346 }
adfa9ca4
KS
347}
348
608a923f
KS
349struct BlockPainterPal<'a> {
350 ls: &'a LocalSearch,
351}
352impl<'a> BlockPainterPal<'a> {
353 fn new(ls: &'a LocalSearch) -> Self { Self{ ls } }
354 fn find_index(&self, pix: UnpackedPixel) -> u8 { self.ls.search(pix) as u8 }
355 fn put_fill(&self, bstate: &BlockState, dst: &mut [u8], dstride: usize) -> u8 {
356 let fill_val = self.find_index(bstate.fill_val);
357 for line in dst.chunks_mut(dstride) {
358 for i in 0..4 {
359 line[i] = fill_val;
360 }
361 }
362 fill_val
363 }
364 fn put_clr2(&self, bstate: &BlockState, dst: &mut [u8], dstride: usize) -> [u8; 2] {
365 let clr2 = [self.find_index(bstate.clr2[0]), self.find_index(bstate.clr2[1])];
366 for j in 0..4 {
367 for i in 0..4 {
368 if (bstate.clr2_flags & (1 << (i + j * 4))) == 0 {
369 dst[i + j * dstride] = clr2[0];
370 } else {
371 dst[i + j * dstride] = clr2[1];
372 }
373 }
374 }
375 clr2
376 }
377 fn put_clr8(&self, bstate: &BlockState, dst: &mut [u8], dstride: usize) -> [[u8; 4]; 4] {
378 let mut clr8 = [[0; 4]; 4];
379 for (dst, src) in clr8.iter_mut().zip(bstate.clr8.iter()) {
380 for (dst, &src) in dst.iter_mut().zip(src.iter()) {
381 *dst = self.find_index(src);
382 }
383 }
384 let mut clr8_flags = bstate.clr8_flags;
385 let swap = (clr8_flags & 0x8000) == 0;
386 if swap {
387 clr8_flags ^= 0xFF00;
388 }
389 if clr8_flags < 0x9000 {
390 clr8_flags |= 0x1000;
391 }
392 if swap {
393 clr8_flags ^= 0xFF00;
394 }
395 for (j, line) in dst.chunks_mut(dstride).take(4).enumerate() {
396 for (i, el) in line.iter_mut().take(4).enumerate() {
397 let blk_no = (i >> 1) + (j & 2);
398 *el = clr8[blk_no][(!clr8_flags & 1) as usize];
399 clr8_flags >>= 1;
400 }
401 }
402 clr8
403 }
404}
405
406struct BlockWriterPal {}
407impl BlockWriterPal {
408 fn write_fill(bw: &mut ByteWriter, fill_val: u8) -> EncoderResult<()> {
409 bw.write_byte(fill_val)?;
410 bw.write_byte(0x80)?;
411 Ok(())
412 }
413 fn write_clr2(bw: &mut ByteWriter, clr2_flags: u16, clr2: [u8; 2]) -> EncoderResult<()> {
414 bw.write_u16le(clr2_flags)?;
415 bw.write_byte(clr2[0])?;
416 bw.write_byte(clr2[1])?;
417 Ok(())
418 }
419 fn write_clr8(bw: &mut ByteWriter, mut clr8_flags: u16, mut clr8: [[u8; 4]; 4]) -> EncoderResult<()> {
420 if (clr8_flags & 0x8000) == 0 {
421 clr8_flags ^= 0xFF00;
422 clr8[2].swap(0, 1);
423 clr8[3].swap(0, 1);
424 }
425 if clr8_flags < 0x9000 {
426 clr8_flags |= 0x1000;
427 }
428
429 bw.write_u16le(clr8_flags)?;
430 bw.write_byte(clr8[0][0])?;
431 bw.write_byte(clr8[0][1])?;
432 bw.write_byte(clr8[1][0])?;
433 bw.write_byte(clr8[1][1])?;
434 bw.write_byte(clr8[2][0])?;
435 bw.write_byte(clr8[2][1])?;
436 bw.write_byte(clr8[3][0])?;
437 bw.write_byte(clr8[3][1])?;
438 Ok(())
439 }
440}
441
adfa9ca4
KS
442struct BlockPainter15 {}
443impl BlockPainter15 {
444 fn new() -> Self { Self{} }
445 fn put_fill(&self, bstate: &BlockState, dst: &mut [u16], dstride: usize) -> u16 {
446 let fill_val = pack_rgb555(bstate.fill_val);
dab59886
KS
447 for line in dst.chunks_mut(dstride) {
448 for i in 0..4 {
adfa9ca4 449 line[i] = fill_val;
dab59886
KS
450 }
451 }
adfa9ca4 452 fill_val
dab59886 453 }
adfa9ca4
KS
454 fn put_clr2(&self, bstate: &BlockState, dst: &mut [u16], dstride: usize) -> [u16; 2] {
455 let clr2 = [pack_rgb555(bstate.clr2[0]), pack_rgb555(bstate.clr2[1])];
dab59886
KS
456 for j in 0..4 {
457 for i in 0..4 {
adfa9ca4
KS
458 if (bstate.clr2_flags & (1 << (i + j * 4))) == 0 {
459 dst[i + j * dstride] = clr2[0];
dab59886 460 } else {
adfa9ca4 461 dst[i + j * dstride] = clr2[1];
dab59886
KS
462 }
463 }
464 }
adfa9ca4 465 clr2
dab59886 466 }
adfa9ca4
KS
467 fn put_clr8(&self, bstate: &BlockState, dst: &mut [u16], dstride: usize) -> [[u16; 4]; 4] {
468 let mut clr8 = [[0; 4]; 4];
469 for (dst, src) in clr8.iter_mut().zip(bstate.clr8.iter()) {
470 for (dst, &src) in dst.iter_mut().zip(src.iter()) {
471 *dst = pack_rgb555(src);
472 }
473 }
b4c5fc31
KS
474 let mut clr8_flags = bstate.clr8_flags;
475 for (j, line) in dst.chunks_mut(dstride).take(4).enumerate() {
476 for (i, el) in line.iter_mut().take(4).enumerate() {
477 let blk_no = (i >> 1) + (j & 2);
478 *el = clr8[blk_no][(!clr8_flags & 1) as usize];
479 clr8_flags >>= 1;
480 }
dab59886 481 }
adfa9ca4 482 clr8
dab59886 483 }
adfa9ca4
KS
484}
485
486struct BlockWriter15 {}
487impl BlockWriter15 {
488 fn write_fill(bw: &mut ByteWriter, fill_val: u16) -> EncoderResult<()> {
489 bw.write_u16le(fill_val | 0x8000)?;
dab59886
KS
490 Ok(())
491 }
adfa9ca4
KS
492 fn write_clr2(bw: &mut ByteWriter, clr2_flags: u16, clr2: [u16; 2]) -> EncoderResult<()> {
493 bw.write_u16le(clr2_flags)?;
494 bw.write_u16le(clr2[0])?;
495 bw.write_u16le(clr2[1])?;
dab59886
KS
496 Ok(())
497 }
b4c5fc31
KS
498 fn write_clr8(bw: &mut ByteWriter, mut clr8_flags: u16, mut clr8: [[u16; 4]; 4]) -> EncoderResult<()> {
499 if (clr8_flags & 0x8000) != 0 {
500 clr8_flags ^= 0xFF00;
501 clr8[2].swap(0, 1);
502 clr8[3].swap(0, 1);
503 }
adfa9ca4
KS
504 bw.write_u16le(clr8_flags)?;
505 bw.write_u16le(clr8[0][0] | 0x8000)?;
506 bw.write_u16le(clr8[0][1])?;
507 bw.write_u16le(clr8[1][0])?;
508 bw.write_u16le(clr8[1][1])?;
509 bw.write_u16le(clr8[2][0])?;
510 bw.write_u16le(clr8[2][1])?;
511 bw.write_u16le(clr8[3][0])?;
512 bw.write_u16le(clr8[3][1])?;
dab59886
KS
513 Ok(())
514 }
515}
516
517struct MSVideo1Encoder {
518 stream: Option<NAStreamRef>,
519 pkt: Option<NAPacket>,
608a923f
KS
520 pool8: NAVideoBufferPool<u8>,
521 pool15: NAVideoBufferPool<u16>,
522 lastfrm8: Option<NAVideoBufferRef<u8>>,
523 lastfrm15: Option<NAVideoBufferRef<u16>>,
dab59886
KS
524 quality: u8,
525 frmcount: u8,
c9c7f648 526 key_int: u8,
608a923f
KS
527
528 pal_mode: bool,
529 pal: [UnpackedPixel; 256],
530 ls: LocalSearch,
dab59886
KS
531}
532
533impl MSVideo1Encoder {
534 fn new() -> Self {
535 Self {
536 stream: None,
537 pkt: None,
608a923f
KS
538 pool8: NAVideoBufferPool::new(2),
539 pool15: NAVideoBufferPool::new(2),
540 lastfrm8: None,
541 lastfrm15: None,
dab59886
KS
542 quality: 0,
543 frmcount: 0,
c9c7f648 544 key_int: 25,
608a923f
KS
545
546 pal_mode: false,
547 pal: [UnpackedPixel::default(); 256],
548 ls: LocalSearch::new(),
dab59886
KS
549 }
550 }
adfa9ca4 551 fn get_block(src: &[u16], sstride: usize, buf: &mut [UnpackedPixel; 16]) {
dab59886 552 for (line, dst) in src.chunks(sstride).zip(buf.chunks_mut(4)) {
adfa9ca4
KS
553 for (dst, src) in dst.iter_mut().zip(line.iter()) {
554 *dst = src.unpack();
555 }
b55da0ef
KS
556 }
557 }
608a923f
KS
558 fn get_block8(src: &[u8], sstride: usize, buf: &mut [UnpackedPixel; 16], pal: &[UnpackedPixel; 256]) {
559 for (line, dst) in src.chunks(sstride).zip(buf.chunks_mut(4)) {
560 for (dst, src) in dst.iter_mut().zip(line.iter()) {
561 *dst = pal[usize::from(*src)];
562 }
563 }
564 }
dab59886
KS
565 fn write_skips(bw: &mut ByteWriter, skips: usize) -> EncoderResult<()> {
566 bw.write_u16le((skips as u16) | 0x8400)?;
567 Ok(())
568 }
608a923f
KS
569 fn encode_inter_rgb555(bw: &mut ByteWriter, cur_frm: &mut NAVideoBuffer<u16>, in_frm: &NAVideoBuffer<u16>, prev_frm: &NAVideoBuffer<u16>, quality: u8) -> EncoderResult<bool> {
570 let (skip_threshold, fill_threshold) = map_quality_15bit(quality);
dab59886
KS
571 let mut is_intra = true;
572 let src = in_frm.get_data();
573 let sstride = in_frm.get_stride(0);
574 let soff = in_frm.get_offset(0);
575 let (w, h) = in_frm.get_dimensions(0);
576 let rsrc = prev_frm.get_data();
577 let rstride = prev_frm.get_stride(0);
578 let roff = prev_frm.get_offset(0);
579 let dstride = cur_frm.get_stride(0);
580 let doff = cur_frm.get_offset(0);
581 let dst = cur_frm.get_data_mut().unwrap();
582 let mut skip_run = 0;
adfa9ca4 583 let bpainter = BlockPainter15::new();
e6aaad5c 584 for ((sstrip, rstrip), dstrip) in src[soff..].chunks(sstride * 4).take(h / 4).zip(rsrc[roff..].chunks(rstride * 4)).zip(dst[doff..].chunks_mut(dstride * 4)) {
dab59886 585 for x in (0..w).step_by(4) {
adfa9ca4
KS
586 let mut buf = [UnpackedPixel::default(); 16];
587 let mut refbuf = [UnpackedPixel::default(); 16];
dab59886
KS
588 Self::get_block(&sstrip[x..], sstride, &mut buf);
589 Self::get_block(&rstrip[x..], rstride, &mut refbuf);
590
591 let mut skip_dist = 0;
592 for (pix, rpix) in buf.iter().zip(refbuf.iter()) {
adfa9ca4 593 skip_dist += dist_core(*rpix, pix);
dab59886 594 }
b55da0ef 595 if skip_dist <= skip_threshold {
dab59886
KS
596 skip_run += 1;
597 is_intra = false;
3c470781
KS
598 for (dst, src) in dstrip[x..].chunks_mut(dstride).zip(rstrip[x..].chunks(rstride)).take(4) {
599 dst[..4].copy_from_slice(&src[..4]);
b55da0ef 600 }
dab59886
KS
601 if skip_run == 1023 {
602 Self::write_skips(bw, skip_run)?;
603 skip_run = 0;
604 }
605 continue;
606 }
607
608 let mut bstate = BlockState::default();
609 bstate.calc_stats(&buf);
610
611 let dst = &mut dstrip[x..];
3c470781 612 if skip_dist <= bstate.fill_dist && skip_dist * 2 <= bstate.clr2_dist {
dab59886
KS
613 skip_run += 1;
614 is_intra = false;
adfa9ca4
KS
615 for (dst, src) in dst.chunks_mut(dstride).zip(rstrip[x..].chunks(rstride)).take(4) {
616 dst[..4].copy_from_slice(&src[..4]);
617 }
dab59886
KS
618 if skip_run == 1023 {
619 Self::write_skips(bw, skip_run)?;
620 skip_run = 0;
621 }
b55da0ef
KS
622 } else if bstate.fill_dist <= fill_threshold ||
623 bstate.fill_dist <= bstate.clr2_dist {
adfa9ca4 624 let fill_val = bpainter.put_fill(&bstate, dst, dstride);
dab59886
KS
625 if skip_run != 0 {
626 Self::write_skips(bw, skip_run)?;
627 skip_run = 0;
628 }
adfa9ca4 629 BlockWriter15::write_fill(bw, fill_val)?;
dab59886 630 } else if bstate.clr8_dist < bstate.clr2_dist {
adfa9ca4 631 let clr8 = bpainter.put_clr8(&bstate, dst, dstride);
dab59886
KS
632 if skip_run != 0 {
633 Self::write_skips(bw, skip_run)?;
634 skip_run = 0;
635 }
b4c5fc31 636 BlockWriter15::write_clr8(bw, bstate.clr8_flags, clr8)?;
dab59886 637 } else {
adfa9ca4 638 let clr2 = bpainter.put_clr2(&bstate, dst, dstride);
dab59886
KS
639 if skip_run != 0 {
640 Self::write_skips(bw, skip_run)?;
641 skip_run = 0;
642 }
adfa9ca4 643 BlockWriter15::write_clr2(bw, bstate.clr2_flags, clr2)?;
dab59886
KS
644 }
645 }
646 }
647 if skip_run != 0 {
648 Self::write_skips(bw, skip_run)?;
649 }
650 if is_intra {
651 bw.write_u16le(0)?;
652 } //xxx: something for inter?
653 Ok(is_intra)
654 }
608a923f
KS
655 fn encode_intra_rgb555(bw: &mut ByteWriter, cur_frm: &mut NAVideoBuffer<u16>, in_frm: &NAVideoBuffer<u16>, quality: u8) -> EncoderResult<bool> {
656 let (_, fill_threshold) = map_quality_15bit(quality);
dab59886
KS
657 let src = in_frm.get_data();
658 let sstride = in_frm.get_stride(0);
659 let soff = in_frm.get_offset(0);
660 let (w, h) = in_frm.get_dimensions(0);
661 let dstride = cur_frm.get_stride(0);
662 let doff = cur_frm.get_offset(0);
663 let dst = cur_frm.get_data_mut().unwrap();
adfa9ca4 664 let bpainter = BlockPainter15::new();
e6aaad5c 665 for (sstrip, dstrip) in src[soff..].chunks(sstride * 4).take(h / 4).zip(dst[doff..].chunks_mut(dstride * 4)) {
dab59886 666 for x in (0..w).step_by(4) {
adfa9ca4 667 let mut buf = [UnpackedPixel::default(); 16];
dab59886
KS
668 Self::get_block(&sstrip[x..], sstride, &mut buf);
669 let mut bstate = BlockState::default();
670 bstate.calc_stats(&buf);
671
672 let dst = &mut dstrip[x..];
b55da0ef
KS
673 if bstate.fill_dist <= fill_threshold ||
674 bstate.fill_dist <= bstate.clr2_dist {
adfa9ca4
KS
675 let fill_val = bpainter.put_fill(&bstate, dst, dstride);
676 BlockWriter15::write_fill(bw, fill_val)?;
dab59886 677 } else if bstate.clr8_dist < bstate.clr2_dist {
adfa9ca4 678 let clr8 = bpainter.put_clr8(&bstate, dst, dstride);
b4c5fc31 679 BlockWriter15::write_clr8(bw, bstate.clr8_flags, clr8)?;
dab59886 680 } else {
adfa9ca4
KS
681 let clr2 = bpainter.put_clr2(&bstate, dst, dstride);
682 BlockWriter15::write_clr2(bw, bstate.clr2_flags, clr2)?;
dab59886
KS
683 }
684 }
685 }
686 bw.write_u16le(0)?;
687 Ok(true)
688 }
608a923f
KS
689 fn encode_inter_pal(bw: &mut ByteWriter, cur_frm: &mut NAVideoBuffer<u8>, in_frm: &NAVideoBuffer<u8>, prev_frm: &NAVideoBuffer<u8>, quality: u8, pal: &[UnpackedPixel; 256], ls: &LocalSearch) -> EncoderResult<bool> {
690 let (skip_threshold, fill_threshold) = map_quality_pal(quality);
691 let mut is_intra = true;
692 let src = in_frm.get_data();
693 let sstride = in_frm.get_stride(0);
694 let soff = in_frm.get_offset(0);
695 let (w, h) = in_frm.get_dimensions(0);
696 let rsrc = prev_frm.get_data();
697 let rstride = prev_frm.get_stride(0);
698 let roff = prev_frm.get_offset(0);
699 let dstride = cur_frm.get_stride(0);
700 let doff = cur_frm.get_offset(0);
701 let dst = cur_frm.get_data_mut().unwrap();
702 let mut skip_run = 0;
703 let bpainter = BlockPainterPal::new(ls);
e6aaad5c 704 for ((sstrip, rstrip), dstrip) in src[soff..].chunks(sstride * 4).take(h / 4).zip(rsrc[roff..].chunks(rstride * 4)).zip(dst[doff..].chunks_mut(dstride * 4)) {
608a923f
KS
705 for x in (0..w).step_by(4) {
706 let mut buf = [UnpackedPixel::default(); 16];
707 let mut refbuf = [UnpackedPixel::default(); 16];
708 Self::get_block8(&sstrip[x..], sstride, &mut buf, pal);
709 Self::get_block8(&rstrip[x..], rstride, &mut refbuf, pal);
710
711 let mut skip_dist = 0;
712 for (pix, rpix) in buf.iter().zip(refbuf.iter()) {
713 skip_dist += dist_core(*rpix, pix);
714 }
715 if skip_dist <= skip_threshold {
716 skip_run += 1;
717 is_intra = false;
718 for (dst, src) in dstrip[x..].chunks_mut(dstride).zip(rstrip[x..].chunks(rstride)).take(4) {
719 dst[..4].copy_from_slice(&src[..4]);
720 }
721 if skip_run == 1023 {
722 Self::write_skips(bw, skip_run)?;
723 skip_run = 0;
724 }
725 continue;
726 }
727
728 let mut bstate = BlockState::new_pal();
729 bstate.calc_stats(&buf);
730
731 let dst = &mut dstrip[x..];
732 if skip_dist <= bstate.fill_dist && skip_dist * 2 <= bstate.clr2_dist {
733 skip_run += 1;
734 is_intra = false;
735 for (dst, src) in dst.chunks_mut(dstride).zip(rstrip[x..].chunks(rstride)).take(4) {
736 dst[..4].copy_from_slice(&src[..4]);
737 }
738 if skip_run == 1023 {
739 Self::write_skips(bw, skip_run)?;
740 skip_run = 0;
741 }
742 } else if bstate.fill_dist <= fill_threshold ||
743 bstate.fill_dist <= bstate.clr2_dist {
744 let fill_val = bpainter.put_fill(&bstate, dst, dstride);
745 if skip_run != 0 {
746 Self::write_skips(bw, skip_run)?;
747 skip_run = 0;
748 }
749 BlockWriterPal::write_fill(bw, fill_val)?;
750 } else if bstate.clr8_dist < bstate.clr2_dist {
751 let clr8 = bpainter.put_clr8(&bstate, dst, dstride);
752 if skip_run != 0 {
753 Self::write_skips(bw, skip_run)?;
754 skip_run = 0;
755 }
756 BlockWriterPal::write_clr8(bw, bstate.clr8_flags, clr8)?;
757 } else {
758 let clr2 = bpainter.put_clr2(&bstate, dst, dstride);
759 if skip_run != 0 {
760 Self::write_skips(bw, skip_run)?;
761 skip_run = 0;
762 }
763 BlockWriterPal::write_clr2(bw, bstate.clr2_flags, clr2)?;
764 }
765 }
766 }
767 if skip_run != 0 {
768 Self::write_skips(bw, skip_run)?;
769 }
770 if is_intra {
771 bw.write_u16le(0)?;
772 } //xxx: something for inter?
773 Ok(is_intra)
774 }
775 fn encode_intra_pal(bw: &mut ByteWriter, cur_frm: &mut NAVideoBuffer<u8>, in_frm: &NAVideoBuffer<u8>, quality: u8, pal: &[UnpackedPixel; 256], ls: &LocalSearch) -> EncoderResult<bool> {
776 let (_, fill_threshold) = map_quality_pal(quality);
777 let src = in_frm.get_data();
778 let sstride = in_frm.get_stride(0);
779 let soff = in_frm.get_offset(0);
780 let (w, h) = in_frm.get_dimensions(0);
781 let dstride = cur_frm.get_stride(0);
782 let doff = cur_frm.get_offset(0);
783 let dst = cur_frm.get_data_mut().unwrap();
784 let bpainter = BlockPainterPal::new(ls);
e6aaad5c 785 for (sstrip, dstrip) in src[soff..].chunks(sstride * 4).take(h / 4).zip(dst[doff..].chunks_mut(dstride * 4)) {
608a923f
KS
786 for x in (0..w).step_by(4) {
787 let mut buf = [UnpackedPixel::default(); 16];
788 Self::get_block8(&sstrip[x..], sstride, &mut buf, pal);
789 let mut bstate = BlockState::new_pal();
790 bstate.calc_stats(&buf);
791
792 let dst = &mut dstrip[x..];
793 if bstate.fill_dist <= fill_threshold ||
794 bstate.fill_dist <= bstate.clr2_dist {
795 let fill_val = bpainter.put_fill(&bstate, dst, dstride);
796 BlockWriterPal::write_fill(bw, fill_val)?;
797 } else if bstate.clr8_dist < bstate.clr2_dist {
798 let clr8 = bpainter.put_clr8(&bstate, dst, dstride);
799 BlockWriterPal::write_clr8(bw, bstate.clr8_flags, clr8)?;
800 } else {
801 let clr2 = bpainter.put_clr2(&bstate, dst, dstride);
802 BlockWriterPal::write_clr2(bw, bstate.clr2_flags, clr2)?;
803 }
804 }
805 }
806 bw.write_u16le(0)?;
807 Ok(true)
808 }
dab59886
KS
809}
810
811const RGB555_FORMAT: NAPixelFormaton = NAPixelFormaton {
812 model: ColorModel::RGB(RGBSubmodel::RGB), components: 3,
813 comp_info: [
814 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 10, comp_offs: 0, next_elem: 2 }),
815 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 5, comp_offs: 0, next_elem: 2 }),
816 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 0, comp_offs: 0, next_elem: 2 }),
817 None, None],
818 elem_size: 2, be: false, alpha: false, palette: false };
819
820impl NAEncoder for MSVideo1Encoder {
821 fn negotiate_format(&self, encinfo: &EncodeParameters) -> EncoderResult<EncodeParameters> {
822 match encinfo.format {
823 NACodecTypeInfo::None => {
6f263099
KS
824 Ok(EncodeParameters {
825 format: NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, true, RGB555_FORMAT)),
826 ..Default::default() })
dab59886 827 },
4efceb69 828 NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
dab59886 829 NACodecTypeInfo::Video(vinfo) => {
608a923f
KS
830 let oformat = if vinfo.format == PAL8_FORMAT { PAL8_FORMAT } else { RGB555_FORMAT };
831 let outinfo = NAVideoInfo::new((vinfo.width + 3) & !3, (vinfo.height + 3) & !3, true, oformat);
d722ffe9 832 let mut ofmt = *encinfo;
dab59886
KS
833 ofmt.format = NACodecTypeInfo::Video(outinfo);
834 Ok(ofmt)
835 }
836 }
837 }
2757a028 838 fn get_capabilities(&self) -> u64 { ENC_CAPS_SKIPFRAME }
dab59886
KS
839 fn init(&mut self, stream_id: u32, encinfo: EncodeParameters) -> EncoderResult<NAStreamRef> {
840 match encinfo.format {
841 NACodecTypeInfo::None => Err(EncoderError::FormatError),
842 NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
843 NACodecTypeInfo::Video(vinfo) => {
608a923f 844 if vinfo.format != RGB555_FORMAT && vinfo.format != PAL8_FORMAT {
dab59886
KS
845 return Err(EncoderError::FormatError);
846 }
847 if ((vinfo.width | vinfo.height) & 3) != 0 {
848 return Err(EncoderError::FormatError);
849 }
850
608a923f 851 let out_info = NAVideoInfo::new(vinfo.width, vinfo.height, true, vinfo.format);
4efceb69 852 let info = NACodecInfo::new("msvideo1", NACodecTypeInfo::Video(out_info), None);
a480a0de 853 let mut stream = NAStream::new(StreamType::Video, stream_id, info, encinfo.tb_num, encinfo.tb_den, 0);
2ff56201
KS
854 stream.set_num(stream_id as usize);
855 let stream = stream.into_ref();
608a923f
KS
856 self.pal_mode = vinfo.format.is_paletted();
857
858 if !self.pal_mode {
859 if self.pool15.prealloc_video(out_info, 2).is_err() {
860 return Err(EncoderError::AllocError);
861 }
862 } else {
863 if self.pool8.prealloc_video(out_info, 2).is_err() {
864 return Err(EncoderError::AllocError);
865 }
dab59886
KS
866 }
867
868 self.stream = Some(stream.clone());
869 self.quality = encinfo.quality;
c8db9313 870
dab59886
KS
871 Ok(stream)
872 },
873 }
874 }
875 fn encode(&mut self, frm: &NAFrame) -> EncoderResult<()> {
876 let buf = frm.get_buffer();
99123344
KS
877 if frm.frame_type == FrameType::Skip {
878 if let Some(ref stream) = self.stream {
879 let mut dbuf = Vec::with_capacity(4);
880 let mut gw = GrowableMemoryWriter::new_write(&mut dbuf);
881 let mut bw = ByteWriter::new(&mut gw);
882
883 let vinfo = stream.get_info().get_properties().get_video_info().unwrap();
884 let mut nskips = ((vinfo.get_width() + 3) / 4) * ((vinfo.get_height() + 3) / 4);
885 while nskips >= 1023 {
886 Self::write_skips(&mut bw, 1023)?;
887 nskips -= 1023;
888 }
889 if nskips > 0 {
890 Self::write_skips(&mut bw, nskips)?;
891 }
892 self.pkt = Some(NAPacket::new(self.stream.clone().unwrap(), frm.ts, false, dbuf));
893 self.frmcount += 1;
894 if self.frmcount == self.key_int {
895 self.frmcount = 0;
896 }
897 return Ok(());
898 } else {
899 return Err(EncoderError::Bug);
900 }
901 }
dab59886 902 if let Some(ref vbuf) = buf.get_vbuf16() {
608a923f
KS
903 if self.pal_mode {
904 return Err(EncoderError::InvalidParameters);
905 }
906 let mut cur_frm = self.pool15.get_free().unwrap();
dab59886
KS
907 let mut dbuf = Vec::with_capacity(4);
908 let mut gw = GrowableMemoryWriter::new_write(&mut dbuf);
909 let mut bw = ByteWriter::new(&mut gw);
910 if self.frmcount == 0 {
608a923f 911 self.lastfrm15 = None;
dab59886 912 }
608a923f
KS
913 let is_intra = if let Some(ref prev_buf) = self.lastfrm15 {
914 Self::encode_inter_rgb555(&mut bw, &mut cur_frm, vbuf, prev_buf, self.quality)?
dab59886 915 } else {
608a923f 916 Self::encode_intra_rgb555(&mut bw, &mut cur_frm, vbuf, self.quality)?
dab59886 917 };
608a923f 918 self.lastfrm15 = Some(cur_frm);
dab59886
KS
919 self.pkt = Some(NAPacket::new(self.stream.clone().unwrap(), frm.ts, is_intra, dbuf));
920 self.frmcount += 1;
c9c7f648 921 if self.frmcount == self.key_int {
dab59886
KS
922 self.frmcount = 0;
923 }
924 Ok(())
608a923f
KS
925 } else if let Some(ref vbuf) = buf.get_vbuf() {
926 if !self.pal_mode {
927 return Err(EncoderError::InvalidParameters);
928 }
929 let src = vbuf.get_data();
930 let pal = &src[vbuf.get_offset(1)..];
931 let mut pal_changed = false;
932 for (cur_pal, new_pal) in self.pal.iter_mut().zip(pal.chunks_exact(3)) {
933 let (cur_clr, luma) = cur_pal.split_at_mut(3);
934 let new_clr = [u16::from(new_pal[0]), u16::from(new_pal[1]), u16::from(new_pal[2])];
e6aaad5c 935 if cur_clr != new_clr {
608a923f
KS
936 pal_changed = true;
937 cur_clr.copy_from_slice(&new_clr);
938 luma[0] = rgb2y(cur_clr[0], cur_clr[1], cur_clr[2]);
939 }
940 }
941
942 if pal_changed {
943 self.ls.recalculate(&self.pal);
944 }
945
946 let mut cur_frm = self.pool8.get_free().unwrap();
947 let mut dbuf = Vec::with_capacity(4);
948 let mut gw = GrowableMemoryWriter::new_write(&mut dbuf);
949 let mut bw = ByteWriter::new(&mut gw);
950 if self.frmcount == 0 {
951 self.lastfrm8 = None;
952 }
953 let is_intra = if let Some(ref prev_buf) = self.lastfrm8 {
954 Self::encode_inter_pal(&mut bw, &mut cur_frm, vbuf, prev_buf, self.quality, &self.pal, &self.ls)?
955 } else {
956 Self::encode_intra_pal(&mut bw, &mut cur_frm, vbuf, self.quality, &self.pal, &self.ls)?
957 };
958 self.lastfrm8 = Some(cur_frm);
959 let mut pkt = NAPacket::new(self.stream.clone().unwrap(), frm.ts, is_intra, dbuf);
960 if pal_changed {
961 let mut epal = [0; 1024];
962 for (dst, src) in epal.chunks_mut(4).zip(self.pal.iter()) {
963 dst[0] = src[0] as u8;
964 dst[1] = src[1] as u8;
965 dst[2] = src[2] as u8;
966 }
967 pkt.add_side_data(NASideData::Palette(true, Arc::new(epal)));
968 }
969 self.pkt = Some(pkt);
970 self.frmcount += 1;
971 if self.frmcount == self.key_int {
972 self.frmcount = 0;
973 }
974 Ok(())
dab59886
KS
975 } else {
976 Err(EncoderError::InvalidParameters)
977 }
978 }
979 fn get_packet(&mut self) -> EncoderResult<Option<NAPacket>> {
980 let mut npkt = None;
981 std::mem::swap(&mut self.pkt, &mut npkt);
982 Ok(npkt)
983 }
984 fn flush(&mut self) -> EncoderResult<()> {
985 self.frmcount = 0;
986 Ok(())
987 }
988}
989
c9c7f648
KS
990const ENCODER_OPTS: &[NAOptionDefinition] = &[
991 NAOptionDefinition {
992 name: KEYFRAME_OPTION, description: KEYFRAME_OPTION_DESC,
993 opt_type: NAOptionDefinitionType::Int(Some(0), Some(128)) },
994];
995
20766f15 996impl NAOptionHandler for MSVideo1Encoder {
c9c7f648
KS
997 fn get_supported_options(&self) -> &[NAOptionDefinition] { ENCODER_OPTS }
998 fn set_options(&mut self, options: &[NAOption]) {
999 for option in options.iter() {
1000 for opt_def in ENCODER_OPTS.iter() {
1001 if opt_def.check(option).is_ok() {
1002 match option.name {
1003 KEYFRAME_OPTION => {
1004 if let NAValue::Int(intval) = option.value {
1005 self.key_int = intval as u8;
1006 }
1007 },
1008 _ => {},
1009 };
1010 }
1011 }
1012 }
1013 }
1014 fn query_option_value(&self, name: &str) -> Option<NAValue> {
1015 match name {
1016 KEYFRAME_OPTION => Some(NAValue::Int(i64::from(self.key_int))),
1017 _ => None,
1018 }
1019 }
20766f15
KS
1020}
1021
dab59886
KS
1022pub fn get_encoder() -> Box<dyn NAEncoder + Send> {
1023 Box::new(MSVideo1Encoder::new())
1024}
1025
1026#[cfg(test)]
1027mod test {
1028 use nihav_core::codecs::*;
1029 use nihav_core::demuxers::*;
1030 use nihav_core::muxers::*;
1031 use crate::*;
1032 use nihav_commonfmt::*;
1033 use nihav_codec_support::test::enc_video::*;
1034 use super::RGB555_FORMAT;
1035
1036 #[test]
608a923f
KS
1037 fn test_ms_video1_encoder_pal() {
1038 let mut dmx_reg = RegisteredDemuxers::new();
1039 generic_register_all_demuxers(&mut dmx_reg);
1040 let mut dec_reg = RegisteredDecoders::new();
1041 generic_register_all_decoders(&mut dec_reg);
1042 ms_register_all_decoders(&mut dec_reg);
1043 let mut mux_reg = RegisteredMuxers::new();
1044 generic_register_all_muxers(&mut mux_reg);
1045 let mut enc_reg = RegisteredEncoders::new();
1046 ms_register_all_encoders(&mut enc_reg);
1047
1048 // sample: https://samples.mplayerhq.hu/V-codecs/RLE/mplayer-msrle-4bit.avi
1049 let dec_config = DecoderTestParams {
1050 demuxer: "avi",
1051 in_name: "assets/MS/mplayer-msrle-4bit.avi",
1052 stream_type: StreamType::Video,
1053 limit: Some(3),
1054 dmx_reg, dec_reg,
1055 };
1056 let enc_config = EncoderTestParams {
1057 muxer: "avi",
1058 enc_name: "msvideo1",
1059 out_name: "msvideo1pal.avi",
1060 mux_reg, enc_reg,
1061 };
1062 let dst_vinfo = NAVideoInfo {
1063 width: 0,
1064 height: 0,
1065 format: PAL8_FORMAT,
1066 flipped: true,
1067 bits: 8,
1068 };
1069 let enc_params = EncodeParameters {
1070 format: NACodecTypeInfo::Video(dst_vinfo),
1071 quality: 0,
1072 bitrate: 0,
1073 tb_num: 0,
1074 tb_den: 0,
1075 flags: 0,
1076 };
1077 //test_encoding_to_file(&dec_config, &enc_config, enc_params, &[]);
1078 test_encoding_md5(&dec_config, &enc_config, enc_params, &[],
2bf1f233 1079 &[0x5afaf853, 0xd53ba9dd, 0x630f53e7, 0x41b33a36]);
608a923f
KS
1080 }
1081
1082 #[test]
1083 fn test_ms_video1_encoder_rgb555() {
dab59886
KS
1084 let mut dmx_reg = RegisteredDemuxers::new();
1085 generic_register_all_demuxers(&mut dmx_reg);
1086 let mut dec_reg = RegisteredDecoders::new();
78fb6560
KS
1087 generic_register_all_decoders(&mut dec_reg);
1088 ms_register_all_decoders(&mut dec_reg);
dab59886
KS
1089 let mut mux_reg = RegisteredMuxers::new();
1090 generic_register_all_muxers(&mut mux_reg);
1091 let mut enc_reg = RegisteredEncoders::new();
1092 ms_register_all_encoders(&mut enc_reg);
1093
886cde48 1094 // sample: https://samples.mplayerhq.hu/V-codecs/UCOD/TalkingHead_352x288.avi
dab59886
KS
1095 let dec_config = DecoderTestParams {
1096 demuxer: "avi",
1097 in_name: "assets/Misc/TalkingHead_352x288.avi",
1098 stream_type: StreamType::Video,
c75dce78 1099 limit: Some(3),
dab59886
KS
1100 dmx_reg, dec_reg,
1101 };
1102 let enc_config = EncoderTestParams {
1103 muxer: "avi",
1104 enc_name: "msvideo1",
1105 out_name: "msvideo1.avi",
1106 mux_reg, enc_reg,
1107 };
1108 let dst_vinfo = NAVideoInfo {
1109 width: 0,
1110 height: 0,
1111 format: RGB555_FORMAT,
1112 flipped: true,
30940e74 1113 bits: 16,
dab59886
KS
1114 };
1115 let enc_params = EncodeParameters {
1116 format: NACodecTypeInfo::Video(dst_vinfo),
b55da0ef 1117 quality: 80,
dab59886
KS
1118 bitrate: 0,
1119 tb_num: 0,
1120 tb_den: 0,
1121 flags: 0,
1122 };
b09ecc09
KS
1123 //test_encoding_to_file(&dec_config, &enc_config, enc_params, &[]);
1124 test_encoding_md5(&dec_config, &enc_config, enc_params, &[],
2bf1f233 1125 &[0xb3175a7b, 0x4a6cb45e, 0x526f3f5d, 0xaa1574cc]);
dab59886
KS
1126 }
1127}