]> git.nihav.org Git - nihav.git/blame - nihav-realmedia/src/codecs/rv40enc/mod.rs
avimux: do not record palette change chunks in OpenDML index
[nihav.git] / nihav-realmedia / src / codecs / rv40enc / mod.rs
CommitLineData
4965a5e5
KS
1use std::collections::VecDeque;
2use std::str::FromStr;
3
4use nihav_core::codecs::*;
5use nihav_core::io::byteio::*;
6use nihav_core::io::bitwriter::*;
7
8mod bitstream;
9use bitstream::*;
10
d92111a8
KS
11#[allow(clippy::eq_op)]
12#[allow(clippy::identity_op)]
13#[allow(clippy::too_many_arguments)]
4965a5e5
KS
14mod dsp;
15use dsp::loop_filter_frame;
16
17mod estimator;
18use estimator::*;
19
d92111a8 20#[allow(clippy::too_many_arguments)]
4965a5e5
KS
21mod mb_coding;
22use mb_coding::*;
23
24mod motion_est;
25use motion_est::*;
26
27mod ratectl;
28use ratectl::*;
29pub use ratectl::RateDistMetric;
30
31mod types;
32pub use types::*;
33
34const DEBUG_BIT_FRAMENO: u8 = 0;
35const DEBUG_BIT_SLICE_SIZE: u8 = 1;
36const DEBUG_BIT_PSNR: u8 = 2;
37const DEBUG_BIT_RATECTL: u8 = 3;
38const DEBUG_FLAG_BITS: &[(&str, u8)] = &[
39 ("frameno", DEBUG_BIT_FRAMENO),
40 ("slicesize", DEBUG_BIT_SLICE_SIZE),
41 ("psnr", DEBUG_BIT_PSNR),
42 ("rc", DEBUG_BIT_RATECTL),
43];
44
45#[derive(Clone,Copy,Default)]
46struct DebugFlags {
47 flags: u32,
48}
49
50impl DebugFlags {
51 fn new() -> Self { Self::default() }
52 fn is_set(self, bit: u8) -> bool { (self.flags & (1 << bit)) != 0 }
53 fn parse(&mut self, args: &str) {
54 self.flags = 0;
55 for arg in args.split('+') {
56 for &(name, bit) in DEBUG_FLAG_BITS.iter() {
57 if name == arg {
58 self.flags += 1 << bit;
59 }
60 }
61 }
62 }
63}
64
65impl std::fmt::Display for DebugFlags {
66 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
67 let mut flags = String::new();
68 let mut first = true;
69 for &(name, bit) in DEBUG_FLAG_BITS.iter() {
70 if self.is_set(bit) {
71 if !first {
72 flags.push('+');
73 }
74 flags.push_str(name);
75 first = false;
76 }
77 }
78 write!(f, "{}", flags)
79 }
80}
81
82struct StaticFrameOrder {
83 groups: Vec<(FrameType, usize)>,
84 start: bool,
85 cur_grp: usize,
86 cur_frm: usize,
87}
88
89impl StaticFrameOrder {
90 /*fn new() -> Self {
91 Self {
92 groups: vec![(FrameType::I, 0)],
93 start: true,
94 cur_grp: 0,
95 cur_frm: 0,
96 }
97 }*/
98 fn get_max_grp_len(&self) -> usize {
99 let mut g_len = 1;
100 for &(_, num_b) in self.groups.iter() {
101 g_len = g_len.max(1 + num_b);
102 }
103 g_len
104 }
105 fn peek_next_frame(&self) -> (FrameType, usize) {
106 if !self.start {
107 let grp = &self.groups[self.cur_grp];
108 if self.cur_frm == 0 {
109 (grp.0, grp.1)
110 } else {
111 (FrameType::B, 0)
112 }
113 } else {
114 (FrameType::I, 0)
115 }
116 }
117 fn next_frame(&mut self) -> FrameType {
118 if !self.start {
119 let grp = &self.groups[self.cur_grp];
120 let frm_type = if self.cur_frm == 0 {
121 grp.0
122 } else {
123 FrameType::B
124 };
125 self.cur_frm += 1;
126 if self.cur_frm > grp.1 {
127 self.cur_frm = 0;
128 self.cur_grp += 1;
129 if self.cur_grp >= self.groups.len() {
130 self.cur_grp = 0;
131 }
132 }
133 frm_type
134 } else {
135 self.start = false;
136 self.cur_grp = if self.groups.len() > 1 { 1 } else { 0 };
137 self.cur_frm = 0;
138 FrameType::I
139 }
140 }
141}
142
143impl std::fmt::Display for StaticFrameOrder {
144 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
145 let mut seq = String::with_capacity(self.groups.len() * 2);
146 for &(ftype, brun) in self.groups.iter() {
147 seq.push(match ftype {
148 FrameType::I => 'I',
149 _ => 'P',
150 });
151 for _ in 0..brun {
152 seq.push('B');
153 }
154 }
155 write!(f, "{}", seq)
156 }
157}
158
159struct DynamicFrameOrder {
160 cur_ft: FrameType,
161 next_ft: FrameType,
162 p_count: usize,
163}
164
165const NUM_GOP_KF: usize = 8;
166
167impl DynamicFrameOrder {
168 fn new() -> Self {
169 Self {
170 cur_ft: FrameType::I,
171 next_ft: FrameType::Other,
172 p_count: 0,
173 }
174 }
175 fn peek_next_frame(&self) -> (FrameType, usize) {
176 (self.cur_ft, if self.cur_ft == FrameType::Other || self.next_ft == FrameType::B { 1 } else { 0 })
177 }
178 fn next_frame(&mut self) -> FrameType {
179 if self.cur_ft == FrameType::P {
180 self.p_count += 1;
181 if self.p_count >= NUM_GOP_KF {
182 self.cur_ft = FrameType::I;
183 self.p_count = 0;
184 }
185 }
186 let next = self.cur_ft;
187 self.cur_ft = self.next_ft;
188 self.next_ft = if self.cur_ft != FrameType::B { FrameType::Other } else { FrameType::P };
189 next
190 }
191 fn update(&mut self, ftype: FrameType) {
192 if self.cur_ft == FrameType::Other {
193 self.cur_ft = ftype;
194 if self.cur_ft == FrameType::B {
195 self.cur_ft = FrameType::P;
196 self.next_ft = FrameType::B;
197 } else {
198 self.next_ft = FrameType::Other;
199 }
200 }
201 }
202}
203
204impl std::fmt::Display for DynamicFrameOrder {
205 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
206 write!(f, "dynamic")
207 }
208}
209
210enum FrameOrder {
211 Static(StaticFrameOrder),
212 Dynamic(DynamicFrameOrder),
213}
214
215impl FrameOrder {
216 fn new() -> Self {
217 FrameOrder::Dynamic(DynamicFrameOrder::new())
218 }
219 fn get_max_grp_len(&self) -> usize {
220 match self {
221 FrameOrder::Static(ref order) => order.get_max_grp_len(),
222 FrameOrder::Dynamic(ref _order) => 2,
223 }
224 }
225 fn peek_next_frame(&self) -> (FrameType, usize) {
226 match self {
227 FrameOrder::Static(ref order) => order.peek_next_frame(),
228 FrameOrder::Dynamic(ref order) => order.peek_next_frame(),
229 }
230 }
231 fn next_frame(&mut self) -> FrameType {
232 match self {
233 FrameOrder::Static(ref mut order) => order.next_frame(),
234 FrameOrder::Dynamic(ref mut order) => order.next_frame(),
235 }
236 }
237 fn update(&mut self, ftype: FrameType) {
238 if let FrameOrder::Dynamic(ref mut order) = self {
239 order.update(ftype);
240 }
241 }
242 fn is_dynamic(&self) -> bool { matches!(self, FrameOrder::Dynamic(_)) }
243}
244
245impl std::fmt::Display for FrameOrder {
246 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
247 match *self {
248 FrameOrder::Static(ref order) => order.fmt(f),
249 FrameOrder::Dynamic(ref order) => order.fmt(f),
250 }
251 }
252}
253
254#[derive(Clone,Copy,Debug)]
255enum ParseError {
256 TooShort,
257 TooLong,
258 InvalidValue,
259 InvalidCombination,
260}
261
262impl FromStr for FrameOrder {
263 type Err = ParseError;
264 fn from_str(s: &str) -> Result<Self, Self::Err> {
265 if s == "dynamic" {
266 return Ok(FrameOrder::Dynamic(DynamicFrameOrder::new()));
267 }
268 let mut ftypes = Vec::new();
269 for ch in s.bytes() {
270 match ch {
271 b'I' | b'i' => ftypes.push(FrameType::I),
272 b'P' | b'p' => ftypes.push(FrameType::P),
273 b'B' | b'b' => ftypes.push(FrameType::B),
274 b' ' | b',' => {},
275 _ => return Err(ParseError::InvalidValue),
276 };
277 if ftypes.len() > 16 {
278 return Err(ParseError::TooLong);
279 }
280 }
281 if ftypes.is_empty() {
282 return Err(ParseError::TooShort);
283 }
284 if ftypes[0] != FrameType::I {
285 return Err(ParseError::InvalidCombination);
286 }
287
288 let mut groups = Vec::new();
289 let mut cur_ftype = ftypes[0];
290 let mut cur_run = 0;
291 for &ft in ftypes[1..].iter() {
292 match ft {
293 FrameType::I | FrameType::P => {
294 groups.push((cur_ftype, cur_run));
295 cur_ftype = ft;
296 cur_run = 0;
297 },
298 _ => {
299 cur_run += 1;
300 if cur_run > 4 {
301 return Err(ParseError::InvalidCombination);
302 }
303 },
304 };
305 }
306 groups.push((cur_ftype, cur_run));
307
308 Ok(FrameOrder::Static(StaticFrameOrder{
309 groups,
310 start: true,
311 cur_grp: 0,
312 cur_frm: 0,
313 }))
314 }
315}
316
317struct RV40Encoder {
318 stream: Option<NAStreamRef>,
319 vinfo: NAVideoInfo,
320 width: usize,
321 height: usize,
322 mb_w: usize,
323 mb_h: usize,
324
325 slice_bits: u32,
326 deblock: bool,
327 force_set: Option<usize>,
328
329 fce: FrameComplexityEstimate,
330 mbd: MacroblockDecider,
331 order: FrameOrder,
332 brc: BitRateControl,
333 rdm: RateDistMetric,
334 be: BitsEstimator,
335 me: MotionEstimator,
336 cset: CodeSets,
337
338 sstate: SliceState,
339 mbstate: MBState,
340 mbs: VecDeque<Macroblock>,
341 dblk: Vec<DeblockInfo>,
342
343 qframes: Vec<NAFrame>,
344 frm_pool: NAVideoBufferPool<u8>,
345 ref_p: NAVideoBufferRef<u8>,
346 ref_n: NAVideoBufferRef<u8>,
347 pkts: VecDeque<NAPacket>,
348
349 p_pts: u64,
350 n_pts: u64,
351 last_k_ts: u64,
352 last_b_ts: u64,
353
354 needs_alloc: bool,
355 max_grp_bufs: usize,
356
357 debug_log: DebugFlags,
358
359 refine_b: bool,
360 i4_in_b: bool,
361}
362
363impl RV40Encoder {
364 fn new() -> Self {
365 let vinfo = NAVideoInfo::new(24, 24, false, YUV420_FORMAT);
366 let vt = alloc_video_buffer(vinfo, 4).unwrap();
367 let ref_p = vt.get_vbuf().unwrap();
368 let vt = alloc_video_buffer(vinfo, 4).unwrap();
369 let ref_n = vt.get_vbuf().unwrap();
370 Self {
371 stream: None,
372 vinfo,
373 width: 0,
374 height: 0,
375 mb_w: 0,
376 mb_h: 0,
377
378 slice_bits: 10000,
379 deblock: true,
380 force_set: None,
381
382 fce: FrameComplexityEstimate::new(),
383 mbd: MacroblockDecider::new(),
384 order: FrameOrder::new(),
385 brc: BitRateControl::new(),
386 rdm: RateDistMetric::new(),
387 be: BitsEstimator::new(),
388 me: MotionEstimator::new(),
389 cset: CodeSets::new(),
390
391 sstate: SliceState::new(),
392 mbstate: MBState::new(),
393 mbs: VecDeque::new(),
394 dblk: Vec::new(),
395
396 qframes: Vec::new(),
397 frm_pool: NAVideoBufferPool::new(0),
398 pkts: VecDeque::new(),
399 ref_p, ref_n,
400
401 p_pts: 0,
402 n_pts: 0,
403 last_k_ts: 0,
404 last_b_ts: 0,
405
406 needs_alloc: true,
407 max_grp_bufs: 0,
408
409 debug_log: DebugFlags::new(),
410
411 refine_b: false,
412 i4_in_b: false,
413 }
414 }
415 fn encode_frame(&mut self, frm: NAFrame, frameno: usize) -> EncoderResult<NAPacket> {
416 let ftype = self.order.next_frame();
417 let buf = frm.get_buffer();
418
419 let tinfo = frm.get_time_information();
420 let pts = NATimeInfo::ts_to_time(tinfo.pts.unwrap_or(0), 1000, tinfo.tb_num, tinfo.tb_den);
421 let fpts = (pts & 0x1FFF) as u32;
422
423 let ts_diff = if ftype == FrameType::B {
424 pts.saturating_sub(self.last_k_ts.min(self.last_b_ts)) as u32
425 } else {
426 let diff = pts.saturating_sub(self.last_k_ts) as u32;
427 diff / ((frameno + 1) as u32)
428 };
429
430 if self.debug_log.is_set(DEBUG_BIT_FRAMENO) {
431 println!("encode frame type {} pts {}", ftype, pts);
432 }
433 let is_ref_frame = matches!(ftype, FrameType::I | FrameType::P);
434
435 let tr_d = (self.n_pts - self.p_pts) as u32;
436 let tr_b = (pts - self.p_pts) as u32;
437 if !is_ref_frame {
438 self.mbd.set_b_distance(tr_b, tr_d);
439 }
440
441 let mut rvbuf = if let Some(nfrm) = self.frm_pool.get_free() {
442 nfrm
443 } else {
444 return Err(EncoderError::AllocError);
445 };
446 let mut recon_frm = NASimpleVideoFrame::from_video_buf(&mut rvbuf).unwrap();
447
448 self.be.set_frame_type(ftype);
449 if let Some(ref vbuf) = buf.get_vbuf() {
450 let src = vbuf.get_data();
451
452 if self.brc.rate_ctl_in_use() || self.order.is_dynamic() {
453 self.fce.set_current(vbuf);
454 }
455
456 let complexity = if self.brc.rate_ctl_in_use() {
457 self.fce.get_complexity(ftype)
458 } else { 0 };
459
460 self.mbd.q = self.brc.get_quant(ftype, complexity);
461 self.brc.init_metric(ftype, &mut self.rdm);
462 self.be.set_quant(self.mbd.q);
463 if self.debug_log.is_set(DEBUG_BIT_RATECTL) {
464 println!(" expected frame size {}", self.brc.get_target_size(ftype));
465 println!(" target quantiser {} lambda {} thresholds {} / {}", self.brc.get_last_quant(ftype), self.rdm.lambda, self.rdm.good_enough, self.rdm.p_split_thr);
466 }
467
468 let mut nslices = 0;
469 let mut dvec = Vec::new();
470 let mut mb_idx = 0;
471 let mut slice_starts = Vec::new();
472 let num_mbs = self.mb_w * self.mb_h;
473 while mb_idx < num_mbs {
474 slice_starts.push(dvec.len());
475 let mut bw = BitWriter::new(dvec, BitWriterMode::BE);
476 let slice_start_mb = mb_idx;
477
478 self.mbstate.reset();
479
480 let mut est_bits = 0;
481 while est_bits < self.slice_bits && mb_idx < num_mbs {
482 let mb_x = mb_idx % self.mb_w;
483 let mb_y = mb_idx / self.mb_w;
484 self.sstate.has_t = mb_idx >= slice_start_mb + self.mb_w;
485 self.sstate.has_l = (mb_idx > slice_start_mb) && (mb_x > 0);
486 self.sstate.has_tl = (mb_idx > slice_start_mb + self.mb_w) && (mb_x > 0);
487 self.sstate.has_tr = (mb_idx >= slice_start_mb + self.mb_w - 1) && (mb_x + 1 < self.mb_w);
488 self.sstate.mb_x = mb_x;
489 self.sstate.mb_y = mb_y;
490
491 let offsets = [
492 vbuf.get_offset(0) + mb_x * 16 + mb_y * 16 * vbuf.get_stride(0),
493 vbuf.get_offset(1) + mb_x * 8 + mb_y * 8 * vbuf.get_stride(1),
494 vbuf.get_offset(2) + mb_x * 8 + mb_y * 8 * vbuf.get_stride(2),
495 ];
496 let strides = [vbuf.get_stride(0), vbuf.get_stride(1), vbuf.get_stride(2)];
497 self.mbd.load_mb(src, offsets, strides, &self.sstate);
498
499 self.be.set_pred_mb_type(self.mbstate.get_pred_mbtype(&self.sstate, ftype == FrameType::B));
500 if ftype == FrameType::B {
501 self.mbd.try_b_coding(&self.ref_p, &self.ref_n, &mut self.be, &mut self.me, &self.rdm, &self.mbstate, self.refine_b);
502 }
503 if ftype == FrameType::P {
504 self.mbd.try_p_coding(&self.ref_n, &mut self.be, &mut self.me, &self.rdm, &self.mbstate);
505 }
506 self.mbd.try_intra_16_pred(&mut self.be, &self.rdm);
507 if ftype != FrameType::B || self.i4_in_b {
508 self.mbd.try_intra_4x4_pred(&mut self.be, &self.rdm, &mut self.mbstate);
509 }
510
511 let mb = self.mbd.get_macroblock();
512 est_bits += self.mbd.get_est_bits();
513 self.mbd.recon_mb(&mut recon_frm);
514 self.mbstate.update(&mb.mb_type, mb_x, mb_y);
515
516 if self.deblock {
517 self.dblk[mb_idx].q = self.mbd.q as u8;
518 if ftype == FrameType::I {
519 self.dblk[mb_idx].is_strong = true;
520 self.dblk[mb_idx].cbp_y = 0xFFFF;
521 self.dblk[mb_idx].cbp_c = 0xFF;
522 } else {
523 self.dblk[mb_idx].is_strong = mb.mb_type.is_intra() || mb.mb_type.is_16();
524 let mut cbp = 0u16;
525 let mut mask = 1;
526 for blk in mb.coeffs[..16].iter() {
527 if !blk.is_empty() {
528 cbp |= mask;
529 }
530 mask <<= 1;
531 }
532 self.dblk[mb_idx].cbp_y = cbp;
533 let mut cbp = 0u8;
534 let mut mask = 1;
535 for blk in mb.coeffs[16..24].iter() {
536 if !blk.is_empty() {
537 cbp |= mask;
538 }
539 mask <<= 1;
540 }
541 self.dblk[mb_idx].cbp_c = cbp;
542 }
543 self.mbstate.fill_deblock(&mut self.dblk[mb_idx], &self.sstate);
544 }
545
546 self.mbs.push_back(mb);
547
548 mb_idx += 1;
549 }
550
551 let set_idx = if let Some(idx) = self.force_set {
552 idx
553 } else {
554 let mut hist = [0usize; 17];
555 for mb in self.mbs.iter() {
556 let blocks = if mb.mb_type.is_16() { &mb.coeffs } else { &mb.coeffs[..24] };
557
558 for blk in blocks.iter() {
559 let nz = blk.count_nz();
560 for el in hist[nz..].iter_mut() {
561 *el += 1;
562 }
563 }
564 }
565 BitsEstimator::decide_set(&hist)
566 };
567
568 let start_bits = bw.tell();
569 write_slice_header(&mut bw, ftype, self.mbd.q, set_idx, self.deblock, fpts);
570 if ftype == FrameType::I {
571 write_slice_dimensions(&mut bw, self.width, self.height);
572 } else {
573 bw.write1(); // keep dimensions flag
574 }
575 write_slice_mb_idx(&mut bw, slice_start_mb, num_mbs);
576
577 mb_idx = slice_start_mb;
578 let mut skip_count = 0;
579 self.cset.init(self.mbd.q, set_idx);
580 while let Some(mb) = self.mbs.pop_front() {
581 if bw.tell() > start_bits + (self.slice_bits as usize) {
582 break;
583 }
584 let mb_x = mb_idx % self.mb_w;
585 let mb_y = mb_idx / self.mb_w;
586 self.sstate.has_t = mb_idx >= slice_start_mb + self.mb_w;
587 self.sstate.has_l = (mb_idx > slice_start_mb) && (mb_x > 0);
588 self.sstate.has_tl = (mb_idx > slice_start_mb + self.mb_w) && (mb_x > 0);
589 self.sstate.has_tr = (mb_idx >= slice_start_mb + self.mb_w - 1) && (mb_x + 1 < self.mb_w);
590 self.sstate.mb_x = mb_x;
591 self.sstate.mb_y = mb_y;
592 if mb.mb_type.is_skip() {
593 skip_count += 1;
594 } else {
595 if skip_count > 0 {
596 write_skip_count(&mut bw, skip_count);
597 skip_count = 0;
598 } else if ftype != FrameType::I {
599 bw.write1(); // zero skip count
600 }
601
602 write_mb_header(&mut bw, ftype, &self.sstate, &self.mbstate);
603 self.cset.set_params(&mb.mb_type);
604 self.cset.write_coeffs(&mut bw, &mb.coeffs);
605 }
606 mb_idx += 1;
607 }
608 self.mbs.clear();
609 if skip_count > 0 {
610 write_skip_count(&mut bw, skip_count);
611 }
612 while (bw.tell() & 7) != 0 {
613 bw.write0();
614 }
615 if self.debug_log.is_set(DEBUG_BIT_SLICE_SIZE) {
616 println!(" slice {}..{} wrote {} bits / estimated {} bits", slice_start_mb, mb_idx, bw.tell(), est_bits);
617 }
618 dvec = bw.end();
619 nslices += 1;
620 }
621 for _ in 0..(nslices * 8 + 1) {
622 dvec.insert(0, 0);
623 }
624 dvec[0] = (nslices - 1) as u8;
625 for (i, &off) in slice_starts.iter().enumerate() {
626 dvec[i * 8 + 4] = 1;
627 write_u32be(&mut dvec[i * 8 + 5..], off as u32)?;
628 }
629 if self.debug_log.is_set(DEBUG_BIT_RATECTL) {
630 println!(" got frame size {}", dvec.len());
631 }
632
633 if is_ref_frame && self.deblock {
634 loop_filter_frame(&mut recon_frm, &self.dblk, self.mb_w, self.mb_h);
635 }
636
637 if self.debug_log.is_set(DEBUG_BIT_PSNR) {
e6aaad5c 638 let psnr = calc_psnr(vbuf, &rvbuf);
4965a5e5
KS
639 println!(" encoded frame PSNR {} size {}", psnr, dvec.len());
640 }
641
642 if is_ref_frame {
643 std::mem::swap(&mut self.ref_p, &mut self.ref_n);
644 self.ref_n = rvbuf;
645
646 self.p_pts = self.n_pts;
647 self.n_pts = pts;
648
649 self.mbstate.swap_mvs();
650 }
651
652 if is_ref_frame {
653 if self.last_k_ts > self.last_b_ts {
654 self.last_b_ts = self.last_k_ts;
655 }
656 self.last_k_ts = pts;
657 self.fce.update_ref();
658 } else {
659 self.last_b_ts = pts;
660 }
661
662 self.brc.update_stats(ftype, dvec.len(), ts_diff);
663
664 Ok(NAPacket::new(self.stream.clone().unwrap(), frm.ts, ftype == FrameType::I, dvec))
665 } else {
666 Err(EncoderError::InvalidParameters)
667 }
668 }
669}
670
671fn calc_psnr(pic1: &NAVideoBuffer<u8>, pic2: &NAVideoBuffer<u8>) -> f64 {
672 let data1 = pic1.get_data();
673 let data2 = pic2.get_data();
674 let mut sum = 0u64;
675 let mut size = 0;
676 for comp in 0..3 {
677 let (w, h) = pic1.get_dimensions(comp);
678 size += w * h;
679 for (line1, line2) in data1[pic1.get_offset(comp)..].chunks(pic1.get_stride(comp)).zip(
680 data2[pic2.get_offset(comp)..].chunks(pic2.get_stride(comp))).take(h) {
681 for (&pix1, &pix2) in line1[..w].iter().zip(line2.iter()) {
e6aaad5c 682 let diff = (i32::from(pix1) - i32::from(pix2)).unsigned_abs();
4965a5e5
KS
683 sum += u64::from(diff * diff);
684 }
685 }
686 }
687 if size > 0 {
688 48.13080360867910341240 - 10.0 * ((sum as f64) / (size as f64)).log10()
689 } else {
690 std::f64::INFINITY
691 }
692}
693
694impl NAEncoder for RV40Encoder {
695 fn negotiate_format(&self, encinfo: &EncodeParameters) -> EncoderResult<EncodeParameters> {
696 match encinfo.format {
697 NACodecTypeInfo::None => {
698 Ok(EncodeParameters {
699 format: NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, false, YUV420_FORMAT)),
700 ..Default::default() })
701 },
702 NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
703 NACodecTypeInfo::Video(vinfo) => {
704 let outinfo = NAVideoInfo::new((vinfo.width + 15) & !15, (vinfo.height + 15) & !15, false, YUV420_FORMAT);
705 let mut ofmt = *encinfo;
706 ofmt.format = NACodecTypeInfo::Video(outinfo);
707 Ok(ofmt)
708 }
709 }
710 }
711 fn get_capabilities(&self) -> u64 { 0 }
712 fn init(&mut self, stream_id: u32, encinfo: EncodeParameters) -> EncoderResult<NAStreamRef> {
713 match encinfo.format {
714 NACodecTypeInfo::None => Err(EncoderError::FormatError),
715 NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
716 NACodecTypeInfo::Video(vinfo) => {
717 if vinfo.format != YUV420_FORMAT {
718 return Err(EncoderError::FormatError);
719 }
720 if ((vinfo.width | vinfo.height) & 15) != 0 {
721 return Err(EncoderError::FormatError);
722 }
723 if (vinfo.width | vinfo.height) >= (1 << 12) {
724 return Err(EncoderError::FormatError);
725 }
726
727 // 32-bit flags (VBR, bframes, slices, something else) and 32-bit version
728 let edata = vec![0x01, 0x08, 0x10, 0x20, 0x40, 0x00, 0x80, 0x00];
729 let out_info = NAVideoInfo::new(vinfo.width, vinfo.height, false, vinfo.format);
730 let info = NACodecInfo::new("realvideo4", NACodecTypeInfo::Video(out_info), Some(edata));
731 let mut stream = NAStream::new(StreamType::Video, stream_id, info, encinfo.tb_num, encinfo.tb_den, 0);
732 stream.set_num(stream_id as usize);
733 let stream = stream.into_ref();
734
735 self.stream = Some(stream.clone());
736
737 self.width = vinfo.width;
738 self.height = vinfo.height;
739 self.mb_w = (vinfo.width + 15) >> 4;
740 self.mb_h = (vinfo.height + 15) >> 4;
741
742 if self.mb_w * self.mb_h > 9216 {
743 return Err(EncoderError::FormatError);
744 }
745
746 if (1..=100u8).contains(&encinfo.quality) {
747 self.brc.set_force_quality(Some(encinfo.quality));
748 } else {
749 self.brc.set_force_quality(None);
750 }
751 self.brc.set_bitrate(encinfo.bitrate);
752
753 self.vinfo = out_info;
754 let max_frames = self.order.get_max_grp_len();
755 self.frm_pool.set_dec_bufs(max_frames + 3);
756 self.max_grp_bufs = max_frames;
757 self.needs_alloc = true;
758
759 self.fce.resize(self.width, self.height);
760 self.mbstate.resize(self.mb_w, self.mb_h);
761 self.mbd.resize(self.mb_w);
762 self.dblk.resize(self.mb_w * self.mb_h, DeblockInfo::default());
763
764 Ok(stream)
765 },
766 }
767 }
768 fn encode(&mut self, frm: &NAFrame) -> EncoderResult<()> {
769 if self.needs_alloc {
770 self.frm_pool.prealloc_video(self.vinfo, 4)?;
771 self.ref_n = self.frm_pool.get_free().unwrap();
772 self.ref_p = self.frm_pool.get_free().unwrap();
773 self.needs_alloc = false;
774 }
775 if let Some(ref vbuf) = frm.get_buffer().get_vbuf() {
776 if let Some(dbuf) = self.frm_pool.get_copy(vbuf) {
777 let newfrm = NAFrame::new(frm.ts, frm.frame_type, frm.key, frm.get_info(), NABufferType::Video(dbuf));
778 self.qframes.push(newfrm);
779
780 loop {
781 let (mut ftype, mut frame_pos) = self.order.peek_next_frame();
782 if frame_pos >= self.qframes.len() {
783 break;
784 }
785
786 if ftype == FrameType::Other {
787 if self.qframes.len() < 2 {
788 return Err(EncoderError::Bug);
789 }
790 if let (Some(ref frm1), Some(ref frm2)) = (self.qframes[0].get_buffer().get_vbuf(), self.qframes[1].get_buffer().get_vbuf()) {
791 let is_b = self.fce.decide_b_frame(frm1, frm2);
792 ftype = if is_b {
793 frame_pos = 1;
794 FrameType::B
795 } else {
796 frame_pos = 0;
797 FrameType::P
798 };
799 } else {
800 return Err(EncoderError::Bug);
801 }
802 self.order.update(ftype);
803 }
804
805 let frm = self.qframes.remove(frame_pos);
806 let pkt = self.encode_frame(frm, frame_pos)?;
807 self.pkts.push_back(pkt);
808 }
809 Ok(())
810 } else {
811 Err(EncoderError::AllocError)
812 }
813 } else {
814 Err(EncoderError::FormatError)
815 }
816 }
817 fn get_packet(&mut self) -> EncoderResult<Option<NAPacket>> {
818 Ok(self.pkts.pop_front())
819 }
820 fn flush(&mut self) -> EncoderResult<()> {
821 Ok(())
822 }
823}
824
825const DEBUG_LOG_OPTION: &str = "debug";
826const SLICE_SIZE_OPTION: &str = "slice_size";
827const FRAME_ORDER_OPTION: &str = "frame_order";
828const DEBLOCK_OPTION: &str = "loop_filt";
829const QUANT_OPTION: &str = "quant";
830const QUALITY_OPTION: &str = "quality";
831const SET_OPTION: &str = "coding_set";
832const SEARCH_MODE_OPTION: &str = "me_mode";
833const SEARCH_RANGE_OPTION: &str = "me_range";
834const SEARCH_THR_OPTION: &str = "me_thr";
835const B_REFINE_OPTION: &str = "refine_b";
836const I4_IN_B_OPTION: &str = "i4_in_b";
837const B_OFFSET_OPTION: &str = "b_offset";
838
839const ENCODER_OPTS: &[NAOptionDefinition] = &[
840 NAOptionDefinition {
841 name: DEBUG_LOG_OPTION, description: "debug flags",
842 opt_type: NAOptionDefinitionType::String(None) },
843 NAOptionDefinition {
844 name: SLICE_SIZE_OPTION, description: "soft slice size limit in bits",
845 opt_type: NAOptionDefinitionType::Int(Some(4096), Some(100000)) },
846 NAOptionDefinition {
847 name: FRAME_ORDER_OPTION, description: "frame order (e.g. IBBPBB)",
848 opt_type: NAOptionDefinitionType::String(None) },
849 NAOptionDefinition {
850 name: DEBLOCK_OPTION, description: "in-loop filter",
851 opt_type: NAOptionDefinitionType::Bool },
852 NAOptionDefinition {
853 name: QUANT_OPTION, description: "force quantiser (-1 = none)",
854 opt_type: NAOptionDefinitionType::Int(Some(-1), Some(31)) },
855 NAOptionDefinition {
856 name: QUALITY_OPTION, description: "force quality (-1 = none)",
857 opt_type: NAOptionDefinitionType::Int(Some(-1), Some(100)) },
858 NAOptionDefinition {
859 name: SET_OPTION, description: "force coding set (-1 = none)",
860 opt_type: NAOptionDefinitionType::Int(Some(-1), Some(3)) },
861 NAOptionDefinition {
862 name: SEARCH_MODE_OPTION, description: "motion search mode",
863 opt_type: NAOptionDefinitionType::String(Some(MVSearchMode::get_possible_modes())) },
864 NAOptionDefinition {
865 name: SEARCH_RANGE_OPTION, description: "motion search range",
866 opt_type: NAOptionDefinitionType::Int(Some(0), Some(256)) },
867 NAOptionDefinition {
868 name: SEARCH_THR_OPTION, description: "motion search cut-off threshold",
869 opt_type: NAOptionDefinitionType::Int(Some(0), Some(1048576)) },
870 NAOptionDefinition {
871 name: B_REFINE_OPTION, description: "better ME for B-frames",
872 opt_type: NAOptionDefinitionType::Bool },
873 NAOptionDefinition {
874 name: I4_IN_B_OPTION, description: "allow intra 4x4 coding in B-frames",
875 opt_type: NAOptionDefinitionType::Bool },
876 NAOptionDefinition {
877 name: B_OFFSET_OPTION, description: "B-frame quantiser offset",
878 opt_type: NAOptionDefinitionType::Int(Some(0), Some(16)) },
879];
880
881impl NAOptionHandler for RV40Encoder {
882 fn get_supported_options(&self) -> &[NAOptionDefinition] { ENCODER_OPTS }
883 fn set_options(&mut self, options: &[NAOption]) {
884 for option in options.iter() {
885 for opt_def in ENCODER_OPTS.iter() {
886 if opt_def.check(option).is_ok() {
887 match option.name {
888 DEBUG_LOG_OPTION => {
889 if let NAValue::String(ref strval) = option.value {
890 self.debug_log.parse(strval);
891 }
892 },
893 SLICE_SIZE_OPTION => {
894 if let NAValue::Int(intval) = option.value {
895 self.slice_bits = intval as u32;
896 }
897 },
898 FRAME_ORDER_OPTION => {
899 if let NAValue::String(ref strval) = option.value {
900 if let Ok(norder) = strval.parse::<FrameOrder>() {
901 self.order = norder;
902 let max_frames = self.order.get_max_grp_len();
903 if max_frames > self.max_grp_bufs {
904 self.frm_pool.set_dec_bufs(max_frames + 3);
905 self.needs_alloc = true;
906 self.max_grp_bufs = max_frames;
907 }
908 } else {
909 println!("Invalid order sequence");
910 }
911 }
912 },
913 DEBLOCK_OPTION => {
914 if let NAValue::Bool(val) = option.value {
915 self.deblock = val;
916 }
917 },
918 QUANT_OPTION => {
919 if let NAValue::Int(val) = option.value {
920 if val != -1 {
921 self.brc.set_force_quant(Some(val as usize));
922 } else {
923 self.brc.set_force_quant(None);
924 }
925 }
926 },
927 QUALITY_OPTION => {
928 if let NAValue::Int(val) = option.value {
929 if val != -1 {
930 self.brc.set_force_quality(Some(val as u8));
931 } else {
932 self.brc.set_force_quality(None);
933 }
934 }
935 },
936 SET_OPTION => {
937 if let NAValue::Int(val) = option.value {
938 self.force_set = if val != -1 { Some(val as usize) } else { None };
939 }
940 },
941 SEARCH_MODE_OPTION => {
942 if let NAValue::String(ref strval) = option.value {
943 if let Ok(mmode) = strval.parse::<MVSearchMode>() {
944 self.me.set_mode(mmode);
945 } else {
946 println!("Invalid mode");
947 }
948 }
949 },
950 SEARCH_RANGE_OPTION => {
951 if let NAValue::Int(val) = option.value {
952 self.me.range = val as i16;
953 }
954 },
955 SEARCH_THR_OPTION => {
956 if let NAValue::Int(val) = option.value {
957 self.me.thresh = val as u32;
958 }
959 },
960 B_REFINE_OPTION => {
961 if let NAValue::Bool(val) = option.value {
962 self.refine_b = val;
963 }
964 },
965 I4_IN_B_OPTION => {
966 if let NAValue::Bool(val) = option.value {
967 self.i4_in_b = val;
968 }
969 },
970 B_OFFSET_OPTION => {
971 if let NAValue::Int(val) = option.value {
972 self.brc.b_offset = val as usize;
973 }
974 },
975 _ => {},
976 };
977 }
978 }
979 }
980 }
981 fn query_option_value(&self, name: &str) -> Option<NAValue> {
982 match name {
983 DEBUG_LOG_OPTION => Some(NAValue::String(self.debug_log.to_string())),
984 SLICE_SIZE_OPTION => Some(NAValue::Int(self.slice_bits as i64)),
985 FRAME_ORDER_OPTION => Some(NAValue::String(self.order.to_string())),
986 DEBLOCK_OPTION => Some(NAValue::Bool(self.deblock)),
987 QUANT_OPTION => Some(NAValue::Int(self.brc.get_force_quant().into())),
988 QUALITY_OPTION => Some(NAValue::Int(self.brc.get_force_quality().into())),
989 SET_OPTION => Some(NAValue::Int(if let Some(set) = self.force_set { set as i64 } else { -1 })),
990 SEARCH_MODE_OPTION => Some(NAValue::String(self.me.get_mode().to_string())),
991 SEARCH_THR_OPTION => Some(NAValue::Int(self.me.thresh.into())),
992 SEARCH_RANGE_OPTION => Some(NAValue::Int(self.me.range.into())),
993 B_REFINE_OPTION => Some(NAValue::Bool(self.refine_b)),
994 I4_IN_B_OPTION => Some(NAValue::Bool(self.i4_in_b)),
995 B_OFFSET_OPTION => Some(NAValue::Int(self.brc.b_offset as i64)),
996 _ => None,
997 }
998 }
999}
1000
1001pub fn get_encoder() -> Box<dyn NAEncoder + Send> {
1002 Box::new(RV40Encoder::new())
1003}
1004
1005#[cfg(test)]
1006mod test {
1007 use nihav_core::codecs::*;
1008 use nihav_core::demuxers::*;
1009 use nihav_core::muxers::*;
1010 use crate::*;
1011 use nihav_codec_support::test::enc_video::*;
1012 use nihav_commonfmt::*;
1013
1014 #[allow(unused_variables)]
1015 fn encode_test(out_name: &'static str, enc_options: &[NAOption], limit: Option<u64>, hash: &[u32; 4]) {
1016 let mut dmx_reg = RegisteredDemuxers::new();
1017 generic_register_all_demuxers(&mut dmx_reg);
1018 let mut dec_reg = RegisteredDecoders::new();
1019 generic_register_all_decoders(&mut dec_reg);
1020 let mut mux_reg = RegisteredMuxers::new();
1021 realmedia_register_all_muxers(&mut mux_reg);
1022 let mut enc_reg = RegisteredEncoders::new();
1023 realmedia_register_all_encoders(&mut enc_reg);
1024
1025 // sample from private collection
1026 let dec_config = DecoderTestParams {
1027 demuxer: "yuv4mpeg",
1028 in_name: "assets/day3b.y4m",
1029 stream_type: StreamType::Video,
1030 limit,
1031 dmx_reg, dec_reg,
1032 };
1033 let enc_config = EncoderTestParams {
1034 muxer: "realmedia",
1035 enc_name: "realvideo4",
1036 out_name,
1037 mux_reg, enc_reg,
1038 };
1039 let dst_vinfo = NAVideoInfo {
1040 width: 0,
1041 height: 0,
1042 format: YUV420_FORMAT,
1043 flipped: false,
1044 bits: 12,
1045 };
1046 let enc_params = EncodeParameters {
1047 format: NACodecTypeInfo::Video(dst_vinfo),
1048 quality: 0,
1049 bitrate: 300000,
1050 tb_num: 0,
1051 tb_den: 0,
1052 flags: 0,
1053 };
1054 //test_encoding_to_file(&dec_config, &enc_config, enc_params, enc_options);
1055 test_encoding_md5(&dec_config, &enc_config, enc_params, enc_options,
1056 hash);
1057 }
1058 #[test]
1059 fn test_rv40_encoder_simple() {
1060 let enc_options = &[
1061 NAOption { name: super::FRAME_ORDER_OPTION, value: NAValue::String("I".to_owned()) },
1062 NAOption { name: super::DEBLOCK_OPTION, value: NAValue::Bool(false) },
1063 NAOption { name: super::QUANT_OPTION, value: NAValue::Int(17) },
1064 NAOption { name: super::SEARCH_MODE_OPTION, value: NAValue::String("diamond".to_owned()) },
1065 ];
1066 encode_test("rv40simple.rmvb", enc_options, Some(10), &[0x03b0d743, 0x36c20dbb, 0x18fa1c9e, 0x4b2b7324]);
1067 }
1068 #[test]
1069 fn test_rv40_encoder_ipb() {
1070 let enc_options = &[
1071 NAOption { name: super::FRAME_ORDER_OPTION, value: NAValue::String("IBPB".to_owned()) },
1072 NAOption { name: super::DEBLOCK_OPTION, value: NAValue::Bool(true) },
1073 NAOption { name: super::QUANT_OPTION, value: NAValue::Int(17) },
1074 NAOption { name: super::SEARCH_MODE_OPTION, value: NAValue::String("hexagon".to_owned()) },
1075 ];
1076 encode_test("rv40ipb.rmvb", enc_options, Some(8), &[0xc382ab0b, 0xbcfbb02a, 0xf12a064f, 0xe6a5c2c3]);
1077 }
1078 #[test]
1079 fn test_rv40_encoder_advanced() {
1080 let enc_options = &[
1081 NAOption { name: super::FRAME_ORDER_OPTION, value: NAValue::String("dynamic".to_owned()) },
1082 NAOption { name: super::DEBLOCK_OPTION, value: NAValue::Bool(true) },
1083 NAOption { name: super::SEARCH_MODE_OPTION, value: NAValue::String("umh".to_owned()) },
1084 ];
1085 encode_test("rv40adv.rmvb", enc_options, Some(8), &[0xc4395f49, 0x0536d5f0, 0x32406834, 0xb7b634be]);
1086 }
1087}