msvideo1enc: prepare workflow for the future paletted mode support
[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
b55da0ef
KS
6fn map_quality(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;
11 let fill_threshold = (10 - (u32::from(quality) / 10).min(10)) * 16;
12 (skip_threshold, fill_threshold)
13 }
14}
15
81d5776a 16trait PixelOps {
adfa9ca4 17 fn unpack(&self) -> UnpackedPixel;
81d5776a
KS
18 fn dist<T: PixelOps>(&self, val: T) -> u32 {
19 dist_core(self.unpack(), &val.unpack())
dab59886 20 }
81d5776a
KS
21}
22
23impl PixelOps for u16 {
adfa9ca4 24 fn unpack(&self) -> UnpackedPixel {
81d5776a
KS
25 let val = *self;
26 let r = (val >> 10) & 0x1F;
27 let g = (val >> 5) & 0x1F;
28 let b = val & 0x1F;
29 [r, g, b, rgb2y(r, g, b)]
dab59886 30 }
81d5776a
KS
31}
32
adfa9ca4 33fn dist_core(val: UnpackedPixel, other: &UnpackedPixel) -> u32 {
81d5776a
KS
34 let sum = val.iter().zip(other.iter()).take(3).fold(0i32,
35 |acc, (&a, &b)| {
36 let diff = i32::from(a) - i32::from(b);
37 acc + diff * diff
38 });
39 sum as u32
40}
41
42
43fn rgb2y(r: u16, g: u16, b: u16) -> u16 {
44 (r * 77 + g * 150 + b * 29) >> 8
45}
46
adfa9ca4 47fn pack_rgb555(val: UnpackedPixel) -> u16 {
81d5776a
KS
48 (val[0] << 10) | (val[1] << 5) | val[2]
49}
50
51#[derive(Default)]
52struct PixelAverage {
adfa9ca4 53 sum: UnpackedPixel,
81d5776a
KS
54 count: u16,
55}
56
57impl PixelAverage {
58 fn new() -> Self { Self::default() }
adfa9ca4 59 fn add(&mut self, val: &UnpackedPixel) {
81d5776a
KS
60 for (dst, &src) in self.sum.iter_mut().zip(val.iter()) {
61 *dst += src;
dab59886 62 }
81d5776a 63 self.count += 1;
dab59886 64 }
adfa9ca4 65 fn get_avg(&self) -> UnpackedPixel {
81d5776a
KS
66 if self.count > 0 {
67 let mut ret = self.sum;
68 for el in ret.iter_mut() {
69 *el /= self.count;
70 }
71 ret
dab59886 72 } else {
81d5776a 73 [0; 4]
dab59886
KS
74 }
75 }
76}
77
81d5776a
KS
78macro_rules! quant_template {
79 ($name:ident, $N:expr) => {
adfa9ca4 80 fn $name(pix: &[UnpackedPixel; $N]) -> ([UnpackedPixel; 2], u16, u32) {
81d5776a
KS
81 let mut avg = PixelAverage::new();
82 let mut maxv = [0; 4];
83 let mut minv = [255; 4];
adfa9ca4
KS
84 for src in pix.iter() {
85 avg.add(src);
86 for ((maxv, minv), &comp) in maxv.iter_mut().zip(minv.iter_mut()).zip(src.iter()) {
81d5776a
KS
87 *maxv = (*maxv).max(comp);
88 *minv = (*minv).min(comp);
89 }
90 }
91 let avg = avg.get_avg();
dab59886 92
81d5776a
KS
93 let mut best_axis = 3;
94 let mut best_dist = maxv[3] - minv[3];
95 for (comp_no, (&minval, &maxval)) in minv.iter().zip(maxv.iter()).enumerate().take(3) {
96 if maxval - minval > best_dist {
97 best_axis = comp_no;
98 best_dist = maxval - minval;
99 }
100 }
101 if best_dist == 0 {
81d5776a 102 let mut dist = 0;
adfa9ca4 103 for el in pix.iter() {
81d5776a
KS
104 dist += dist_core(avg, el);
105 }
adfa9ca4 106 return ([avg; 2], 0, dist);
81d5776a
KS
107 }
108
109 let mut avg1 = PixelAverage::new();
110 let mut avg2 = PixelAverage::new();
111 let mut mask = 0;
112 let mut mask_bit = 1;
adfa9ca4 113 for clr in pix.iter() {
81d5776a
KS
114 if clr[best_axis] > avg[best_axis] {
115 avg2.add(clr);
116 mask |= mask_bit;
117 } else {
118 avg1.add(clr);
119 }
120 mask_bit <<= 1;
121 }
122
123 let clr0 = avg1.get_avg();
124 let clr1 = avg2.get_avg();
125 let mut dist = 0;
adfa9ca4 126 for clr in pix.iter() {
81d5776a
KS
127 let dist0 = dist_core(clr0, clr);
128 let dist1 = dist_core(clr1, clr);
129 dist += dist0.min(dist1);
130 }
adfa9ca4 131 ([clr0, clr1], mask, dist)
dab59886
KS
132 }
133 }
134}
135
81d5776a
KS
136quant_template!(quant2_16pix, 16);
137quant_template!(quant2_4pix, 4);
138
dab59886
KS
139#[derive(Default)]
140struct BlockState {
141 fill_dist: u32,
adfa9ca4 142 fill_val: UnpackedPixel,
dab59886
KS
143 clr2_dist: u32,
144 clr2_flags: u16,
adfa9ca4 145 clr2: [UnpackedPixel; 2],
dab59886
KS
146 clr8_dist: u32,
147 clr8_flags: u16,
adfa9ca4
KS
148 clr8: [[UnpackedPixel; 2]; 4],
149 pal_mode: bool,
dab59886
KS
150}
151
152impl BlockState {
adfa9ca4
KS
153 fn set_fill_val(&mut self, val: UnpackedPixel) {
154 self.fill_val = val;
155 if !self.pal_mode {
156 self.fill_val[0] &= !1;
157 }
158 }
159 fn calc_clrs(buf: &[UnpackedPixel; 16]) -> (Option<UnpackedPixel>, Option<UnpackedPixel>) {
93d1e373 160 let clr0 = buf[0];
adfa9ca4
KS
161 let mut clr1 = clr0;
162 let mut single = true;
93d1e373 163 for &pix in buf[1..].iter() {
adfa9ca4
KS
164 if pix != clr0 {
165 if single {
93d1e373 166 clr1 = pix;
adfa9ca4
KS
167 single = false;
168 } else if pix != clr1 {
169 return (None, None);
93d1e373
KS
170 }
171 }
172 }
adfa9ca4
KS
173 if !single {
174 (Some(clr0), Some(clr1))
175 } else {
176 (Some(clr0), None)
177 }
93d1e373 178 }
adfa9ca4 179 fn calc_stats(&mut self, buf: &[UnpackedPixel; 16]) {
93d1e373
KS
180 let mut filled = false;
181 let mut two_clr = false;
adfa9ca4
KS
182 match Self::calc_clrs(buf) {
183 (Some(clr0), Some(clr1)) => {
184 self.clr2[0] = clr0;
185 self.clr2[1] = clr1;
186 two_clr = true;
187 },
188 (Some(clr0), None) => {
189 self.clr2[0] = clr0;
190 self.clr2[1] = clr0;
191 self.set_fill_val(buf[0]);
93d1e373 192 filled = true;
adfa9ca4
KS
193 two_clr = true;
194 },
195 _ => {},
196 };
93d1e373
KS
197 self.fill_dist = 0;
198 if !filled {
81d5776a 199 let mut avg = PixelAverage::new();
adfa9ca4
KS
200 for pix in buf.iter() {
201 avg.add(pix);
dab59886 202 }
adfa9ca4 203 self.set_fill_val(avg.get_avg());
93d1e373 204 for pix in buf.iter() {
adfa9ca4 205 self.fill_dist += dist_core(self.fill_val, pix);
93d1e373 206 }
dab59886
KS
207 }
208 if self.fill_dist == 0 {
209 self.clr2_dist = std::u32::MAX;
210 self.clr8_dist = std::u32::MAX;
211 return;
212 }
213
214 self.clr2_flags = 0u16;
93d1e373
KS
215 if two_clr {
216 let mut mask = 1;
217 self.clr2_dist = 0;
218 for &pix in buf.iter() {
219 if pix == self.clr2[0] {
220 self.clr2_flags |= mask;
221 } else {
222 }
223 mask <<= 1;
224 }
225 if (self.clr2_flags & 0x8000) != 0 {
226 self.clr2_flags = !self.clr2_flags;
227 self.clr2.swap(0, 1);
228 }
81d5776a
KS
229 } else {
230 let (clrs, mask, dist) = quant2_16pix(&buf);
231 self.clr2 = clrs;
232 self.clr2_flags = mask;
233 self.clr2_dist = dist;
dab59886
KS
234 if (self.clr2_flags & 0x8000) != 0 {
235 self.clr2_flags = !self.clr2_flags;
236 self.clr2.swap(0, 1);
237 }
dab59886
KS
238 }
239 if self.clr2_dist == 0 {
240 self.clr8_dist = std::u32::MAX;
241 return;
242 }
243
adfa9ca4 244 self.clr8 = [[UnpackedPixel::default(); 2]; 4];
dab59886
KS
245 self.clr8_flags = 0;
246 self.clr8_dist = 0;
dab59886
KS
247 for i in 0..4 {
248 let off = (i & 1) * 2 + (i & 2) * 4;
249 let src2 = [buf[off], buf[off + 1], buf[off + 4], buf[off + 5]];
81d5776a
KS
250 let (clrs, mask, dist) = quant2_4pix(&src2);
251 self.clr8[i] = clrs;
252 self.clr8_flags |= mask << (i * 4);
253 self.clr8_dist += dist;
dab59886
KS
254 }
255 if (self.clr8_flags & 0x8000) != 0 {
256 self.clr8_flags ^= 0xF000;
257 self.clr8[3].swap(0, 1);
258 }
259 }
adfa9ca4
KS
260}
261
262struct BlockPainter15 {}
263impl BlockPainter15 {
264 fn new() -> Self { Self{} }
265 fn put_fill(&self, bstate: &BlockState, dst: &mut [u16], dstride: usize) -> u16 {
266 let fill_val = pack_rgb555(bstate.fill_val);
dab59886
KS
267 for line in dst.chunks_mut(dstride) {
268 for i in 0..4 {
adfa9ca4 269 line[i] = fill_val;
dab59886
KS
270 }
271 }
adfa9ca4 272 fill_val
dab59886 273 }
adfa9ca4
KS
274 fn put_clr2(&self, bstate: &BlockState, dst: &mut [u16], dstride: usize) -> [u16; 2] {
275 let clr2 = [pack_rgb555(bstate.clr2[0]), pack_rgb555(bstate.clr2[1])];
dab59886
KS
276 for j in 0..4 {
277 for i in 0..4 {
adfa9ca4
KS
278 if (bstate.clr2_flags & (1 << (i + j * 4))) == 0 {
279 dst[i + j * dstride] = clr2[0];
dab59886 280 } else {
adfa9ca4 281 dst[i + j * dstride] = clr2[1];
dab59886
KS
282 }
283 }
284 }
adfa9ca4 285 clr2
dab59886 286 }
adfa9ca4
KS
287 fn put_clr8(&self, bstate: &BlockState, dst: &mut [u16], dstride: usize) -> [[u16; 4]; 4] {
288 let mut clr8 = [[0; 4]; 4];
289 for (dst, src) in clr8.iter_mut().zip(bstate.clr8.iter()) {
290 for (dst, &src) in dst.iter_mut().zip(src.iter()) {
291 *dst = pack_rgb555(src);
292 }
293 }
dab59886
KS
294 for i in 0..4 {
295 let off = (i & 1) * 2 + (i & 2) * dstride;
adfa9ca4
KS
296 let cur_flg = (bstate.clr8_flags >> (i * 4)) & 0xF;
297 dst[off] = clr8[i][( !cur_flg & 1) as usize];
298 dst[off + 1] = clr8[i][((!cur_flg >> 1) & 1) as usize];
299 dst[off + dstride] = clr8[i][((!cur_flg >> 2) & 1) as usize];
300 dst[off + 1 + dstride] = clr8[i][((!cur_flg >> 3) & 1) as usize];
dab59886 301 }
adfa9ca4 302 clr8
dab59886 303 }
adfa9ca4
KS
304}
305
306struct BlockWriter15 {}
307impl BlockWriter15 {
308 fn write_fill(bw: &mut ByteWriter, fill_val: u16) -> EncoderResult<()> {
309 bw.write_u16le(fill_val | 0x8000)?;
dab59886
KS
310 Ok(())
311 }
adfa9ca4
KS
312 fn write_clr2(bw: &mut ByteWriter, clr2_flags: u16, clr2: [u16; 2]) -> EncoderResult<()> {
313 bw.write_u16le(clr2_flags)?;
314 bw.write_u16le(clr2[0])?;
315 bw.write_u16le(clr2[1])?;
dab59886
KS
316 Ok(())
317 }
adfa9ca4
KS
318 fn write_clr8(bw: &mut ByteWriter, clr8_flags: u16, clr8: &[[u16; 4]; 4]) -> EncoderResult<()> {
319 bw.write_u16le(clr8_flags)?;
320 bw.write_u16le(clr8[0][0] | 0x8000)?;
321 bw.write_u16le(clr8[0][1])?;
322 bw.write_u16le(clr8[1][0])?;
323 bw.write_u16le(clr8[1][1])?;
324 bw.write_u16le(clr8[2][0])?;
325 bw.write_u16le(clr8[2][1])?;
326 bw.write_u16le(clr8[3][0])?;
327 bw.write_u16le(clr8[3][1])?;
dab59886
KS
328 Ok(())
329 }
330}
331
332struct MSVideo1Encoder {
333 stream: Option<NAStreamRef>,
334 pkt: Option<NAPacket>,
335 pool: NAVideoBufferPool<u16>,
336 lastfrm: Option<NAVideoBufferRef<u16>>,
337 quality: u8,
338 frmcount: u8,
c9c7f648 339 key_int: u8,
dab59886
KS
340}
341
342impl MSVideo1Encoder {
343 fn new() -> Self {
344 Self {
345 stream: None,
346 pkt: None,
347 pool: NAVideoBufferPool::new(2),
348 lastfrm: None,
349 quality: 0,
350 frmcount: 0,
c9c7f648 351 key_int: 25,
dab59886
KS
352 }
353 }
adfa9ca4 354 fn get_block(src: &[u16], sstride: usize, buf: &mut [UnpackedPixel; 16]) {
dab59886 355 for (line, dst) in src.chunks(sstride).zip(buf.chunks_mut(4)) {
adfa9ca4
KS
356 for (dst, src) in dst.iter_mut().zip(line.iter()) {
357 *dst = src.unpack();
358 }
b55da0ef
KS
359 }
360 }
dab59886
KS
361 fn write_skips(bw: &mut ByteWriter, skips: usize) -> EncoderResult<()> {
362 bw.write_u16le((skips as u16) | 0x8400)?;
363 Ok(())
364 }
b55da0ef
KS
365 fn encode_inter(bw: &mut ByteWriter, cur_frm: &mut NAVideoBuffer<u16>, in_frm: &NAVideoBuffer<u16>, prev_frm: &NAVideoBuffer<u16>, quality: u8) -> EncoderResult<bool> {
366 let (skip_threshold, fill_threshold) = map_quality(quality);
dab59886
KS
367 let mut is_intra = true;
368 let src = in_frm.get_data();
369 let sstride = in_frm.get_stride(0);
370 let soff = in_frm.get_offset(0);
371 let (w, h) = in_frm.get_dimensions(0);
372 let rsrc = prev_frm.get_data();
373 let rstride = prev_frm.get_stride(0);
374 let roff = prev_frm.get_offset(0);
375 let dstride = cur_frm.get_stride(0);
376 let doff = cur_frm.get_offset(0);
377 let dst = cur_frm.get_data_mut().unwrap();
378 let mut skip_run = 0;
adfa9ca4 379 let bpainter = BlockPainter15::new();
dab59886
KS
380 for ((sstrip, rstrip), dstrip) in (&src[soff..]).chunks(sstride * 4).take(h / 4).zip((&rsrc[roff..]).chunks(rstride * 4)).zip((&mut dst[doff..]).chunks_mut(dstride * 4)) {
381 for x in (0..w).step_by(4) {
adfa9ca4
KS
382 let mut buf = [UnpackedPixel::default(); 16];
383 let mut refbuf = [UnpackedPixel::default(); 16];
dab59886
KS
384 Self::get_block(&sstrip[x..], sstride, &mut buf);
385 Self::get_block(&rstrip[x..], rstride, &mut refbuf);
386
387 let mut skip_dist = 0;
388 for (pix, rpix) in buf.iter().zip(refbuf.iter()) {
adfa9ca4 389 skip_dist += dist_core(*rpix, pix);
dab59886 390 }
b55da0ef 391 if skip_dist <= skip_threshold {
dab59886
KS
392 skip_run += 1;
393 is_intra = false;
b55da0ef 394 if skip_threshold > 0 {
adfa9ca4
KS
395 for (dst, src) in dstrip[x..].chunks_mut(dstride).zip(rstrip[x..].chunks(rstride)).take(4) {
396 dst[..4].copy_from_slice(&src[..4]);
397 }
b55da0ef 398 }
dab59886
KS
399 if skip_run == 1023 {
400 Self::write_skips(bw, skip_run)?;
401 skip_run = 0;
402 }
403 continue;
404 }
405
406 let mut bstate = BlockState::default();
407 bstate.calc_stats(&buf);
408
409 let dst = &mut dstrip[x..];
410 if skip_dist <= bstate.fill_dist {
411 skip_run += 1;
412 is_intra = false;
adfa9ca4
KS
413 for (dst, src) in dst.chunks_mut(dstride).zip(rstrip[x..].chunks(rstride)).take(4) {
414 dst[..4].copy_from_slice(&src[..4]);
415 }
dab59886
KS
416 if skip_run == 1023 {
417 Self::write_skips(bw, skip_run)?;
418 skip_run = 0;
419 }
b55da0ef
KS
420 } else if bstate.fill_dist <= fill_threshold ||
421 bstate.fill_dist <= bstate.clr2_dist {
adfa9ca4 422 let fill_val = bpainter.put_fill(&bstate, dst, dstride);
dab59886
KS
423 if skip_run != 0 {
424 Self::write_skips(bw, skip_run)?;
425 skip_run = 0;
426 }
adfa9ca4 427 BlockWriter15::write_fill(bw, fill_val)?;
dab59886 428 } else if bstate.clr8_dist < bstate.clr2_dist {
adfa9ca4 429 let clr8 = bpainter.put_clr8(&bstate, dst, dstride);
dab59886
KS
430 if skip_run != 0 {
431 Self::write_skips(bw, skip_run)?;
432 skip_run = 0;
433 }
adfa9ca4 434 BlockWriter15::write_clr8(bw, bstate.clr8_flags, &clr8)?;
dab59886 435 } else {
adfa9ca4 436 let clr2 = bpainter.put_clr2(&bstate, dst, dstride);
dab59886
KS
437 if skip_run != 0 {
438 Self::write_skips(bw, skip_run)?;
439 skip_run = 0;
440 }
adfa9ca4 441 BlockWriter15::write_clr2(bw, bstate.clr2_flags, clr2)?;
dab59886
KS
442 }
443 }
444 }
445 if skip_run != 0 {
446 Self::write_skips(bw, skip_run)?;
447 }
448 if is_intra {
449 bw.write_u16le(0)?;
450 } //xxx: something for inter?
451 Ok(is_intra)
452 }
b55da0ef
KS
453 fn encode_intra(bw: &mut ByteWriter, cur_frm: &mut NAVideoBuffer<u16>, in_frm: &NAVideoBuffer<u16>, quality: u8) -> EncoderResult<bool> {
454 let (_, fill_threshold) = map_quality(quality);
dab59886
KS
455 let src = in_frm.get_data();
456 let sstride = in_frm.get_stride(0);
457 let soff = in_frm.get_offset(0);
458 let (w, h) = in_frm.get_dimensions(0);
459 let dstride = cur_frm.get_stride(0);
460 let doff = cur_frm.get_offset(0);
461 let dst = cur_frm.get_data_mut().unwrap();
adfa9ca4 462 let bpainter = BlockPainter15::new();
dab59886
KS
463 for (sstrip, dstrip) in (&src[soff..]).chunks(sstride * 4).take(h / 4).zip((&mut dst[doff..]).chunks_mut(dstride * 4)) {
464 for x in (0..w).step_by(4) {
adfa9ca4 465 let mut buf = [UnpackedPixel::default(); 16];
dab59886
KS
466 Self::get_block(&sstrip[x..], sstride, &mut buf);
467 let mut bstate = BlockState::default();
468 bstate.calc_stats(&buf);
469
470 let dst = &mut dstrip[x..];
b55da0ef
KS
471 if bstate.fill_dist <= fill_threshold ||
472 bstate.fill_dist <= bstate.clr2_dist {
adfa9ca4
KS
473 let fill_val = bpainter.put_fill(&bstate, dst, dstride);
474 BlockWriter15::write_fill(bw, fill_val)?;
dab59886 475 } else if bstate.clr8_dist < bstate.clr2_dist {
adfa9ca4
KS
476 let clr8 = bpainter.put_clr8(&bstate, dst, dstride);
477 BlockWriter15::write_clr8(bw, bstate.clr8_flags, &clr8)?;
dab59886 478 } else {
adfa9ca4
KS
479 let clr2 = bpainter.put_clr2(&bstate, dst, dstride);
480 BlockWriter15::write_clr2(bw, bstate.clr2_flags, clr2)?;
dab59886
KS
481 }
482 }
483 }
484 bw.write_u16le(0)?;
485 Ok(true)
486 }
487}
488
489const RGB555_FORMAT: NAPixelFormaton = NAPixelFormaton {
490 model: ColorModel::RGB(RGBSubmodel::RGB), components: 3,
491 comp_info: [
492 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 10, comp_offs: 0, next_elem: 2 }),
493 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 5, comp_offs: 0, next_elem: 2 }),
494 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 0, comp_offs: 0, next_elem: 2 }),
495 None, None],
496 elem_size: 2, be: false, alpha: false, palette: false };
497
498impl NAEncoder for MSVideo1Encoder {
499 fn negotiate_format(&self, encinfo: &EncodeParameters) -> EncoderResult<EncodeParameters> {
500 match encinfo.format {
501 NACodecTypeInfo::None => {
6f263099
KS
502 Ok(EncodeParameters {
503 format: NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, true, RGB555_FORMAT)),
504 ..Default::default() })
dab59886 505 },
4efceb69 506 NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
dab59886
KS
507 NACodecTypeInfo::Video(vinfo) => {
508 let outinfo = NAVideoInfo::new((vinfo.width + 3) & !3, (vinfo.height + 3) & !3, true, RGB555_FORMAT);
d722ffe9 509 let mut ofmt = *encinfo;
dab59886
KS
510 ofmt.format = NACodecTypeInfo::Video(outinfo);
511 Ok(ofmt)
512 }
513 }
514 }
515 fn init(&mut self, stream_id: u32, encinfo: EncodeParameters) -> EncoderResult<NAStreamRef> {
516 match encinfo.format {
517 NACodecTypeInfo::None => Err(EncoderError::FormatError),
518 NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
519 NACodecTypeInfo::Video(vinfo) => {
520 if vinfo.format != RGB555_FORMAT {
521 return Err(EncoderError::FormatError);
522 }
523 if ((vinfo.width | vinfo.height) & 3) != 0 {
524 return Err(EncoderError::FormatError);
525 }
526
527 let out_info = NAVideoInfo::new(vinfo.width, vinfo.height, true, RGB555_FORMAT);
4efceb69 528 let info = NACodecInfo::new("msvideo1", NACodecTypeInfo::Video(out_info), None);
a480a0de 529 let mut stream = NAStream::new(StreamType::Video, stream_id, info, encinfo.tb_num, encinfo.tb_den, 0);
2ff56201
KS
530 stream.set_num(stream_id as usize);
531 let stream = stream.into_ref();
4efceb69 532 if self.pool.prealloc_video(out_info, 2).is_err() {
dab59886
KS
533 return Err(EncoderError::AllocError);
534 }
535
536 self.stream = Some(stream.clone());
537 self.quality = encinfo.quality;
c8db9313 538
dab59886
KS
539 Ok(stream)
540 },
541 }
542 }
543 fn encode(&mut self, frm: &NAFrame) -> EncoderResult<()> {
544 let buf = frm.get_buffer();
545 if let Some(ref vbuf) = buf.get_vbuf16() {
546 let mut cur_frm = self.pool.get_free().unwrap();
547 let mut dbuf = Vec::with_capacity(4);
548 let mut gw = GrowableMemoryWriter::new_write(&mut dbuf);
549 let mut bw = ByteWriter::new(&mut gw);
550 if self.frmcount == 0 {
551 self.lastfrm = None;
552 }
553 let is_intra = if let Some(ref prev_buf) = self.lastfrm {
554 Self::encode_inter(&mut bw, &mut cur_frm, vbuf, prev_buf, self.quality)?
555 } else {
556 Self::encode_intra(&mut bw, &mut cur_frm, vbuf, self.quality)?
557 };
558 self.lastfrm = Some(cur_frm);
559 self.pkt = Some(NAPacket::new(self.stream.clone().unwrap(), frm.ts, is_intra, dbuf));
560 self.frmcount += 1;
c9c7f648 561 if self.frmcount == self.key_int {
dab59886
KS
562 self.frmcount = 0;
563 }
564 Ok(())
565 } else {
566 Err(EncoderError::InvalidParameters)
567 }
568 }
569 fn get_packet(&mut self) -> EncoderResult<Option<NAPacket>> {
570 let mut npkt = None;
571 std::mem::swap(&mut self.pkt, &mut npkt);
572 Ok(npkt)
573 }
574 fn flush(&mut self) -> EncoderResult<()> {
575 self.frmcount = 0;
576 Ok(())
577 }
578}
579
c9c7f648
KS
580const ENCODER_OPTS: &[NAOptionDefinition] = &[
581 NAOptionDefinition {
582 name: KEYFRAME_OPTION, description: KEYFRAME_OPTION_DESC,
583 opt_type: NAOptionDefinitionType::Int(Some(0), Some(128)) },
584];
585
20766f15 586impl NAOptionHandler for MSVideo1Encoder {
c9c7f648
KS
587 fn get_supported_options(&self) -> &[NAOptionDefinition] { ENCODER_OPTS }
588 fn set_options(&mut self, options: &[NAOption]) {
589 for option in options.iter() {
590 for opt_def in ENCODER_OPTS.iter() {
591 if opt_def.check(option).is_ok() {
592 match option.name {
593 KEYFRAME_OPTION => {
594 if let NAValue::Int(intval) = option.value {
595 self.key_int = intval as u8;
596 }
597 },
598 _ => {},
599 };
600 }
601 }
602 }
603 }
604 fn query_option_value(&self, name: &str) -> Option<NAValue> {
605 match name {
606 KEYFRAME_OPTION => Some(NAValue::Int(i64::from(self.key_int))),
607 _ => None,
608 }
609 }
20766f15
KS
610}
611
dab59886
KS
612pub fn get_encoder() -> Box<dyn NAEncoder + Send> {
613 Box::new(MSVideo1Encoder::new())
614}
615
616#[cfg(test)]
617mod test {
618 use nihav_core::codecs::*;
619 use nihav_core::demuxers::*;
620 use nihav_core::muxers::*;
621 use crate::*;
622 use nihav_commonfmt::*;
623 use nihav_codec_support::test::enc_video::*;
624 use super::RGB555_FORMAT;
625
626 #[test]
627 fn test_ms_video1_encoder() {
628 let mut dmx_reg = RegisteredDemuxers::new();
629 generic_register_all_demuxers(&mut dmx_reg);
630 let mut dec_reg = RegisteredDecoders::new();
78fb6560
KS
631 generic_register_all_decoders(&mut dec_reg);
632 ms_register_all_decoders(&mut dec_reg);
dab59886
KS
633 let mut mux_reg = RegisteredMuxers::new();
634 generic_register_all_muxers(&mut mux_reg);
635 let mut enc_reg = RegisteredEncoders::new();
636 ms_register_all_encoders(&mut enc_reg);
637
886cde48 638 // sample: https://samples.mplayerhq.hu/V-codecs/UCOD/TalkingHead_352x288.avi
dab59886
KS
639 let dec_config = DecoderTestParams {
640 demuxer: "avi",
641 in_name: "assets/Misc/TalkingHead_352x288.avi",
642 stream_type: StreamType::Video,
c75dce78 643 limit: Some(3),
dab59886
KS
644 dmx_reg, dec_reg,
645 };
646 let enc_config = EncoderTestParams {
647 muxer: "avi",
648 enc_name: "msvideo1",
649 out_name: "msvideo1.avi",
650 mux_reg, enc_reg,
651 };
652 let dst_vinfo = NAVideoInfo {
653 width: 0,
654 height: 0,
655 format: RGB555_FORMAT,
656 flipped: true,
30940e74 657 bits: 16,
dab59886
KS
658 };
659 let enc_params = EncodeParameters {
660 format: NACodecTypeInfo::Video(dst_vinfo),
b55da0ef 661 quality: 80,
dab59886
KS
662 bitrate: 0,
663 tb_num: 0,
664 tb_den: 0,
665 flags: 0,
666 };
b09ecc09
KS
667 //test_encoding_to_file(&dec_config, &enc_config, enc_params, &[]);
668 test_encoding_md5(&dec_config, &enc_config, enc_params, &[],
b55da0ef 669 &[0x35d95583, 0xb7431be7, 0xad490677, 0x968a1d84]);
dab59886
KS
670 }
671}