1use std::cell::RefCell;
2use std::rc::Rc;
3use std::vec::Vec;
4use std::{cmp, fmt, io};
5
6use thiserror::Error;
7
8use num_derive::FromPrimitive;
9use num_traits::FromPrimitive;
10
11pub mod frame;
12
13use crate::dec::*;
14use crate::def::*;
15use crate::enc::*;
16use frame::*;
17
18pub const EVC_ERR_BAD_CRC: usize = (201);
23pub const EVC_WARN_CRC_IGNORED: usize = (200);
25pub const EVC_OK: usize = 0;
26
27#[derive(Debug, FromPrimitive, ToPrimitive, PartialOrd, Ord, PartialEq, Eq)]
28pub enum EvcError {
29 EVC_OK_NO_MORE_OUTPUT = 205,
31 EVC_OK_OUTPUT_NOT_AVAILABLE = 204,
33 EVC_OK_DIM_CHANGED = 203,
35 EVC_OK_FLUSH = 202,
37
38 EVC_ERR = (-1), EVC_ERR_INVALID_ARGUMENT = (-101),
40 EVC_ERR_OUT_OF_MEMORY = (-102),
41 EVC_ERR_REACHED_MAX = (-103),
42 EVC_ERR_UNSUPPORTED = (-104),
43 EVC_ERR_UNEXPECTED = (-105),
44 EVC_ERR_UNSUPPORTED_COLORSPACE = (-201),
45 EVC_ERR_MALFORMED_BITSTREAM = (-202),
46 EVC_ERR_EMPTY_PACKET = (-203),
47 EVC_ERR_EMPTY_FRAME = (-204),
48
49 EVC_ERR_UNKNOWN = (-32767), }
51
52impl Default for EvcError {
53 fn default() -> Self {
54 EvcError::EVC_ERR
55 }
56}
57
58pub const NALU_SIZE_FIELD_IN_BYTES: usize = 4;
59
60#[allow(dead_code, non_camel_case_types)]
61#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd, Clone, Copy)]
62pub enum NaluType {
63 EVC_NONIDR_NUT = 0,
64 EVC_IDR_NUT = 1,
65 EVC_SPS_NUT = 24,
66 EVC_PPS_NUT = 25,
67 EVC_APS_NUT = 26,
68 EVC_FD_NUT = 27,
69 EVC_SEI_NUT = 28,
70 EVC_UNKNOWN_NUT,
71}
72
73impl fmt::Display for NaluType {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 use self::NaluType::*;
76 match self {
77 EVC_NONIDR_NUT => write!(f, "Non-IDR"),
78 EVC_IDR_NUT => write!(f, "Instantaneous Decoder Refresh"),
79 EVC_SPS_NUT => write!(f, "Sequence Parameter Se"),
80 EVC_PPS_NUT => write!(f, "Picture Parameter Set"),
81 EVC_APS_NUT => write!(f, "Adaptation Parameter Set"),
82 EVC_FD_NUT => write!(f, "Filler Data"),
83 EVC_SEI_NUT => write!(f, "Supplemental Enhancement Information"),
84 EVC_UNKNOWN_NUT => write!(f, "Unknown"),
85 }
86 }
87}
88
89impl From<u8> for NaluType {
90 fn from(val: u8) -> Self {
91 use self::NaluType::*;
92 match val {
93 0 => EVC_NONIDR_NUT,
94 1 => EVC_IDR_NUT,
95 24 => EVC_SPS_NUT,
96 25 => EVC_PPS_NUT,
97 26 => EVC_APS_NUT,
98 27 => EVC_FD_NUT,
99 28 => EVC_SEI_NUT,
100 _ => EVC_UNKNOWN_NUT,
101 }
102 }
103}
104
105impl Default for NaluType {
106 fn default() -> Self {
107 NaluType::EVC_NONIDR_NUT
108 }
109}
110
111#[allow(dead_code, non_camel_case_types)]
112#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd, Clone, Copy)]
113#[repr(C)]
114pub enum SliceType {
115 EVC_ST_UNKNOWN = 0,
116 EVC_ST_I = 1,
117 EVC_ST_P = 2,
118 EVC_ST_B = 3,
119}
120
121impl fmt::Display for SliceType {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 use self::SliceType::*;
124 match self {
125 EVC_ST_UNKNOWN => write!(f, "Unknown"),
126 EVC_ST_I => write!(f, "I"),
127 EVC_ST_P => write!(f, "P"),
128 EVC_ST_B => write!(f, "B"),
129 }
130 }
131}
132
133impl From<u8> for SliceType {
134 fn from(val: u8) -> Self {
135 use self::SliceType::*;
136 match val {
137 1 => EVC_ST_I,
138 2 => EVC_ST_P,
139 3 => EVC_ST_B,
140 _ => EVC_ST_UNKNOWN,
141 }
142 }
143}
144
145impl Default for SliceType {
146 fn default() -> Self {
147 SliceType::EVC_ST_UNKNOWN
148 }
149}
150
151impl SliceType {
152 #[inline]
153 pub(crate) fn IS_INTRA_SLICE(&self) -> bool {
154 *self == SliceType::EVC_ST_I
155 }
156
157 #[inline]
158 pub(crate) fn IS_INTER_SLICE(&self) -> bool {
159 *self == SliceType::EVC_ST_P || *self == SliceType::EVC_ST_B
160 }
161}
162
163#[derive(Debug, Default)]
167pub struct EvcStat {
168 pub bytes: usize,
170 pub nalu_type: NaluType,
172 pub stype: SliceType,
174 pub fnum: isize,
177 pub poc: isize,
179 pub tid: isize,
181
182 pub refpic_num: [u8; 2],
184 pub refpic: [[isize; 16]; 2], pub ret: usize,
188
189 pub sei_size: usize,
192 pub qp: u8,
195 pub rec: Option<Rc<RefCell<Frame<pel>>>>,
196 pub psnr: Option<[f64; N_C]>,
197}
198
199pub const MAX_NUM_REF_PICS: usize = 21;
200pub const MAX_NUM_ACTIVE_REF_FRAME: usize = 5;
201pub const MAX_NUM_RPLS: usize = 32;
202
203#[derive(Default)]
205pub struct EvcRpl {
206 pub poc: usize,
207 pub tid: usize,
208 pub ref_pic_num: u8,
209 pub ref_pic_active_num: u8,
210 pub ref_pics: [u8; MAX_NUM_REF_PICS],
211 pub pic_type: u8,
212}
213
214pub const MAX_QP_TABLE_SIZE: usize = 58;
215pub const MAX_QP_TABLE_SIZE_EXT: usize = 70;
216
217pub struct EvcChromaTable {
219 pub chroma_qp_table_present_flag: bool,
220 pub same_qp_table_for_chroma: bool,
221 pub global_offset_flag: bool,
222 pub num_points_in_qp_table_minus1: [usize; 2],
223 pub delta_qp_in_val_minus1: [[i8; MAX_QP_TABLE_SIZE]; 2],
224 pub delta_qp_out_val: [[i8; MAX_QP_TABLE_SIZE]; 2],
225}
226
227static default_qp_talbe: [[i8; MAX_QP_TABLE_SIZE]; 2] = [[0; MAX_QP_TABLE_SIZE]; 2];
228impl Default for EvcChromaTable {
229 fn default() -> Self {
230 EvcChromaTable {
231 chroma_qp_table_present_flag: false,
232 same_qp_table_for_chroma: false,
233 global_offset_flag: false,
234 num_points_in_qp_table_minus1: [0; 2],
235 delta_qp_in_val_minus1: default_qp_talbe,
236 delta_qp_out_val: default_qp_talbe,
237 }
238 }
239}
240
241pub enum Data {
242 Empty,
243 RefFrame(Rc<RefCell<Frame<pel>>>),
244 Frame(Option<Frame<pel>>),
245 RefPacket(Rc<RefCell<Packet>>),
246 Packet(Option<Packet>),
247}
248
249#[derive(Debug, Default)]
250pub struct Packet {
251 pub data: Vec<u8>,
252 pub ts: u64,
253}
254
255impl fmt::Display for Packet {
256 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
257 write!(f, "Packet {} - {} bytes", self.ts, self.data.len())
258 }
259}
260
261#[derive(Copy, Clone, Debug, PartialEq, FromPrimitive)]
262#[repr(C)]
263pub enum ChromaSampling {
264 Cs400,
265 Cs420,
266 Cs422,
267 Cs444,
268}
269
270impl Default for ChromaSampling {
271 fn default() -> Self {
272 ChromaSampling::Cs420
273 }
274}
275
276impl From<u8> for ChromaSampling {
277 fn from(val: u8) -> Self {
278 use self::ChromaSampling::*;
279 match val {
280 0 => Cs400,
281 1 => Cs420,
282 2 => Cs422,
283 _ => Cs444,
284 }
285 }
286}
287
288impl ChromaSampling {
289 pub fn sampling_period(self) -> (usize, usize) {
291 use self::ChromaSampling::*;
292 match self {
293 Cs420 => (2, 2),
294 Cs422 => (2, 1),
295 Cs444 => (1, 1),
296 Cs400 => (2, 2),
297 }
298 }
299}
300
301#[derive(Debug, Clone, Copy, PartialEq, FromPrimitive)]
302#[repr(C)]
303pub enum PixelRange {
304 Unspecified = 0,
305 Limited,
306 Full,
307}
308
309impl Default for PixelRange {
310 fn default() -> Self {
311 PixelRange::Unspecified
312 }
313}
314
315#[derive(Clone, Copy, Debug, Default)]
316#[repr(C)]
317pub struct Rational {
318 pub num: u64,
319 pub den: u64,
320}
321
322impl Rational {
323 pub fn new(num: u64, den: u64) -> Self {
324 Rational { num, den }
325 }
326}
327
328#[derive(Clone, Copy, Debug)]
329#[repr(C)]
330pub struct Point {
331 pub x: u16,
332 pub y: u16,
333}
334
335#[derive(Debug, Clone, Copy, Eq, PartialEq, Error)]
337#[non_exhaustive]
338pub enum InvalidConfig {
339 #[error("invalid width {0} (expected >= 16, <= 32767)")]
341 InvalidWidth(usize),
342 #[error("invalid height {0} (expected >= 16, <= 32767)")]
344 InvalidHeight(usize),
345 #[error("invalid rdo lookahead frames {actual} (expected <= {max} and >= {min})")]
347 InvalidRdoLookaheadFrames {
348 actual: usize,
350 max: usize,
352 min: usize,
354 },
355 #[error("invalid max keyframe interval {actual} (expected <= {max})")]
357 InvalidMaxKeyFrameInterval {
358 actual: usize,
360 max: usize,
362 },
363 #[error("invalid framerate numerator {actual} (expected > 0, <= {max})")]
365 InvalidFrameRateNum {
366 actual: u64,
368 max: u64,
370 },
371 #[error("invalid framerate denominator {actual} (expected > 0, <= {max})")]
373 InvalidFrameRateDen {
374 actual: u64,
376 max: u64,
378 },
379
380 #[error("invalid qp {actual} (expected <= {max} and >= {min})")]
382 InvalidQP {
383 actual: u8,
385 max: u8,
387 min: u8,
389 },
390
391 #[error("Invalid Max B Frames")]
392 InvalidMaxBFrames,
393 #[error("Invalid Ref Pic GAP Length")]
394 InvalidRefPicGapLength,
395 #[error("Invalid Hierarchical GOP")]
396 InvalidHierarchicalGOP,
397
398 #[error("The rate control requires a target bitrate")]
400 TargetBitrateNeeded,
401}
402
403pub(crate) const MAX_RDO_LOOKAHEAD_FRAMES: usize = usize::max_value() - 1;
405pub const MAX_MAX_KEY_FRAME_INTERVAL: usize = i32::max_value() as usize / 3;
407
408#[derive(Clone, Copy, Debug, Default)]
409pub struct EncoderConfig {
410 pub width: usize,
413 pub height: usize,
415 pub time_base: Rational,
417 pub fps: u64,
418
419 pub bit_depth: usize,
421 pub chroma_sampling: ChromaSampling,
423
424 pub min_key_frame_interval: usize,
427 pub max_key_frame_interval: usize, pub qp: u8,
432 pub min_qp: u8,
434 pub max_qp: u8,
436 pub bitrate: i32,
438
439 pub cb_qp_offset: i8,
440 pub cr_qp_offset: i8,
441 pub cu_qp_delta_area: u8,
442 pub max_b_frames: u8,
443 pub ref_pic_gap_length: u8,
444 pub closed_gop: bool,
445 pub disable_hgop: bool,
446 pub level: u8,
447 pub enable_cip: bool,
448 pub disable_dbf: bool,
449 pub num_slices_in_pic: usize,
450 pub inter_slice_type: SliceType,
451
452 pub rdo_lookahead_frames: usize,
454 }
459
460impl EncoderConfig {
461 pub fn validate(&self) -> Result<(), InvalidConfig> {
463 use InvalidConfig::*;
464
465 let config = self;
466
467 if config.width < 16 || config.width > u16::max_value() as usize || config.width & 7 != 0 {
468 return Err(InvalidWidth(config.width));
469 }
470 if config.height < 16 || config.height > u16::max_value() as usize || config.height & 7 != 0
471 {
472 return Err(InvalidHeight(config.height));
473 }
474
475 if config.qp < MIN_QUANT || config.qp > MAX_QUANT {
476 return Err(InvalidQP {
477 actual: config.qp,
478 max: MAX_QUANT,
479 min: MIN_QUANT,
480 });
481 }
482
483 if config.max_key_frame_interval > MAX_MAX_KEY_FRAME_INTERVAL {
492 return Err(InvalidMaxKeyFrameInterval {
493 actual: config.max_key_frame_interval,
494 max: MAX_MAX_KEY_FRAME_INTERVAL,
495 });
496 }
497
498 if config.time_base.num == 0 || config.time_base.num > u32::max_value() as u64 {
499 return Err(InvalidFrameRateNum {
500 actual: config.time_base.num,
501 max: u32::max_value() as u64,
502 });
503 }
504 if config.time_base.den == 0 || config.time_base.den > u32::max_value() as u64 {
505 return Err(InvalidFrameRateDen {
506 actual: config.time_base.den,
507 max: u32::max_value() as u64,
508 });
509 }
510
511 if !config.disable_hgop {
512 if !(config.max_b_frames == 0
513 || config.max_b_frames == 1
514 || config.max_b_frames == 3
515 || config.max_b_frames == 7
516 || config.max_b_frames == 15)
517 {
518 return Err(InvalidMaxBFrames);
519 }
520
521 if config.max_b_frames != 0 {
522 if config.max_key_frame_interval % (config.max_b_frames + 1) as usize != 0 {
523 return Err(InvalidHierarchicalGOP);
524 }
525 }
526 }
527
528 if config.ref_pic_gap_length != 0 && config.max_b_frames != 0 {
529 return Err(InvalidMaxBFrames);
530 }
531
532 if config.max_b_frames == 0 {
533 if !(config.ref_pic_gap_length == 1
534 || config.ref_pic_gap_length == 2
535 || config.ref_pic_gap_length == 4
536 || config.ref_pic_gap_length == 8
537 || config.ref_pic_gap_length == 16)
538 {
539 return Err(InvalidRefPicGapLength);
540 }
541 }
542
543 Ok(())
551 }
552}
553
554#[derive(Clone, Copy, Debug, Default)]
556pub struct Config {
557 pub threads: usize,
559
560 pub enc: Option<EncoderConfig>,
562}
563
564pub struct DecoderContext(EvcdCtx);
565pub struct EncoderContext(EvceCtx);
566
567pub enum Context {
568 Invalid(InvalidConfig),
569 Decoder(DecoderContext),
570 Encoder(EncoderContext),
571}
572
573impl Context {
574 pub fn new(cfg: &Config) -> Self {
575 if let Some(cfg_enc) = &cfg.enc {
576 match cfg_enc.validate() {
577 Ok(_) => Context::Encoder(EncoderContext(EvceCtx::new(cfg))),
578 Err(err) => return Context::Invalid(err),
579 }
580 } else {
581 Context::Decoder(DecoderContext(EvcdCtx::new(cfg)))
582 }
583 }
584
585 pub fn push(&mut self, data: &mut Data) -> Result<(), EvcError> {
586 match self {
587 Context::Decoder(ctx) => {
588 if let Data::Packet(pkt) = data {
589 ctx.0.push_pkt(pkt)
590 } else {
591 Err(EvcError::EVC_ERR_EMPTY_PACKET)
592 }
593 }
594 Context::Encoder(ctx) => {
595 if let Data::Frame(frm) = data {
596 ctx.0.push_frm(frm)
597 } else {
598 Err(EvcError::EVC_ERR_EMPTY_FRAME)
599 }
600 }
601 Context::Invalid(_) => Err(EvcError::EVC_ERR_UNSUPPORTED),
602 }
603 }
604
605 pub fn pull(&mut self, data: &mut Data) -> Result<Option<EvcStat>, EvcError> {
606 *data = Data::Empty;
607
608 match self {
609 Context::Decoder(ctx) => {
610 let mut stat = None;
611 let mut pull_frm = false;
612 match ctx.0.decode_nalu() {
613 Ok(st) => {
614 pull_frm = st.fnum >= 0;
615 stat = Some(st);
616 }
617 Err(err) => {
618 if err == EvcError::EVC_OK_FLUSH {
619 pull_frm = true;
620 }
621 }
622 }
623
624 if pull_frm {
625 match ctx.0.pull_frm() {
626 Ok(frame) => *data = Data::RefFrame(frame),
627 Err(err) => {
628 if err != EvcError::EVC_OK_OUTPUT_NOT_AVAILABLE {
629 return Err(err);
630 }
631 }
632 }
633 }
634
635 Ok(stat)
636 }
637 Context::Encoder(ctx) => {
638 let mut stat = None;
639 let mut pull_pkt = false;
640 match ctx.0.encode_frm() {
641 Ok(st) => {
642 pull_pkt = true;
643 stat = Some(st);
644 }
645 Err(err) => {
646 if err != EvcError::EVC_OK_OUTPUT_NOT_AVAILABLE {
647 return Err(err);
648 }
649 }
650 }
651
652 if pull_pkt {
653 let packet = ctx.0.pull_pkt()?;
654 *data = Data::RefPacket(packet);
655 }
656
657 Ok(stat)
658 }
659 Context::Invalid(_) => Err(EvcError::EVC_ERR_UNSUPPORTED),
660 }
661 }
662}