oxideav_h265/lib.rs
1//! # oxideav-h265
2//!
3//! Pure-Rust H.265 / HEVC (ITU-T H.265 | ISO/IEC 23008-2) parser and
4//! decoder, for the [oxideav](https://github.com/OxideAV/oxideav)
5//! framework.
6//!
7//! **Status:** the decoder is end-to-end. [`decode_annexb_sequence`] /
8//! [`SequenceDecoder`] decode whole Annex B byte streams to
9//! output-order pictures, and [`make_decoder`] exposes the same driver
10//! through the [`oxideav_core::Decoder`] registry contract (registered
11//! by [`register`] under `"h265"` / `"hevc"`, accepting Annex B and
12//! `hvcC` / length-prefixed transport). Every Annex B bitstream in the
13//! staged 16-fixture conformance corpus decodes byte-exact, plus
14//! self-built pins for explicit weighted prediction, PCM, dependent
15//! slice segments and per-slice loop-filter flags. [`make_encoder`] is
16//! the PCM-only IDR encoder bootstrap (lossless, conformant, every
17//! packet a random access point) over the write-side stack in
18//! [`encoder`] (bit writer, NAL encapsulation, the §9.3.5 CABAC
19//! encoding engine, parameter-set / slice writers). See `README.md`
20//! for coverage and the remaining gaps (true multi-tile fixtures,
21//! encoder beyond the PCM bootstrap).
22//!
23//! The sections below record the per-round rebuild history of the
24//! subsystems the driver composes.
25//!
26//! **History:** clean-room rebuild (post 2026-05-18 audit).
27//! The latest round adds the §8.6.2 / §8.6.3 / §8.6.4 scaling,
28//! transformation and residual-array construction step — the new
29//! [`transform`] module. [`transform::scale_coefficients`] implements
30//! the §8.6.3 dequantization (the `levelScale` / `m[x][y]` /
31//! `1 << (qP/6)` product, `bdShift` offset-round and
32//! `[coeffMin, coeffMax]` clip of equations 8-300..8-309);
33//! [`transform::inverse_transform`] implements the §8.6.4 separable
34//! inverse transform (the equation-8-316 4x4 DST-VII for `MODE_INTRA`
35//! 4x4 luma and the equations-8-318..8-321 32x32 DCT-II with the
36//! equation-8-317 column subsampling for every other block, plus the
37//! equation-8-314 intermediate offset-round); and
38//! [`transform::residual_block`] orchestrates the §8.6.2 dispatch over
39//! `cu_transquant_bypass_flag` (the equation-8-297 `rotateCoeffs`
40//! pass-through), `transform_skip_flag` (the equation-8-298 `tsShift`
41//! left-shift), and the full scale-then-transform path, applying the
42//! equation-8-299 final `bdShift` offset-round.
43//!
44//! Round 12 finishes the §7.3.2.1 VPS tail through the optional VPS
45//! timing-info block ([`vps::HevcVps`] now carries `max_layer_id`,
46//! `num_layer_sets_minus1`, the `layer_id_included_flag[][]`
47//! inclusion matrix as [`vps::LayerIdInclusionRow`] rows, the
48//! `vps_timing_info_present_flag` block as [`vps::VpsTimingInfo`] —
49//! `u(32)` `num_units_in_tick` / `time_scale`,
50//! `poc_proportional_to_timing_flag` +
51//! `num_ticks_poc_diff_one_minus1`, and `num_hrd_parameters` — plus
52//! `vps_extension_flag`); per-HRD `hrd_parameters()` bodies and the
53//! extension-data payload are surfaced as
54//! [`vps::HevcVps::opaque_tail`].
55//!
56//! Round 11 landed the §9.3 CABAC arithmetic decoding engine
57//! ([`cabac::CabacEngine`] / [`cabac::ContextModel`] / [`cabac::init_type`]):
58//! the §9.3.2.6 engine-register init, the §9.3.2.2 context-variable init
59//! (equations 9-4..9-7), the §9.3.4.3.2 DecodeDecision primitive (with
60//! the Table 9-52 / Table 9-53 LPS-range / state-transition tables), the
61//! §9.3.4.3.3 RenormD loop, the §9.3.4.3.4 DecodeBypass primitive (with
62//! an MSB-first `decode_bypass_bits(n)` helper), the §9.3.4.3.5
63//! DecodeTerminate primitive, and the §9.3.4.3.6 aligned-bypass
64//! alignment hook. The engine ships standalone — independent of the
65//! §9.3.4.2 per-syntax-element binarization / context-index derivation
66//! that the slice-data parser still needs.
67//!
68//! Rounds 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 land the Annex B NAL-unit
69//! byte-stream walker, the §7.3.1.2 NAL header parse, the §7.3.2.1
70//! VPS structural parse (with a §7.3.3 profile_tier_level walk), the
71//! full §7.3.2.2 SPS parse (through the `vui_parameters_present_flag`
72//! / `sps_extension_present_flag` gates, with the VUI body and any
73//! extension payload surfaced as an opaque-bytes tail), the
74//! §7.3.2.3.1 PPS parse (full general body through
75//! `pps_extension_present_flag`, including the tiles and
76//! deblocking-control blocks; the PPS extension bodies are surfaced as
77//! an opaque tail), the §7.3.6.1 slice-segment-header parse —
78//! independent I-slice IDR segments end to end (round 6), and
79//! independent **non-IDR I-slice** segments through the §7.3.6.1 POC +
80//! short-term-RPS + long-term-RPS block end to end (round 7) — and
81//! now (round 8) the §7.3.4 `scaling_list_data()` parse with the
82//! §7.4.5 `ScalingList[sizeId][matrixId][i]` derivation, wired into
83//! both the SPS (`sps_scaling_list_data_present_flag`) and PPS
84//! (`pps_scaling_list_data_present_flag`) paths. The P/B
85//! reference-list / weighted-prediction sub-structures are still
86//! surfaced as an opaque tail.
87//!
88//! ## What works today
89//!
90//! * Annex B byte-stream splitting (3- and 4-byte start codes,
91//! trailing-zero padding tolerance).
92//! * §7.3.1.2 NAL header parse: `forbidden_zero_bit`,
93//! `nal_unit_type`, `nuh_layer_id`, and `TemporalId` (derived
94//! from `nuh_temporal_id_plus1`).
95//! * §7.4.1.1 emulation-prevention byte strip (`0x00 0x00 0x03` →
96//! `0x00 0x00`).
97//! * MSB-first bit reader with `u(n)` and 0-th-order
98//! unsigned-Exp-Golomb `ue(v)` (§9.2) descriptors.
99//! * §7.3.2.1 [`vps::HevcVps`] — vps_id, base-layer / max-layers /
100//! sub-layers / temporal-nesting flags, reserved-0xFFFF validation,
101//! the §7.3.3 profile_tier_level walk (general profile + level +
102//! per-sub-layer present-flag gates and `sub_layer_level_idc`), and
103//! the per-sub-layer DPB / reorder / latency triple loop.
104//! * §7.3.2.2 [`sps::SeqParameterSet`] — vps-id back-reference,
105//! max-sub-layers / nesting flag, the §7.3.3 PTL re-walk,
106//! `chroma_format_idc` / `separate_colour_plane_flag`,
107//! `pic_width_in_luma_samples` / `pic_height_in_luma_samples`,
108//! conformance-window quad, `bit_depth_{luma,chroma}_minus8`,
109//! `log2_max_pic_order_cnt_lsb_minus4`, the per-sub-layer
110//! DPB / reorder / latency triple loop, the four
111//! `log2_*_block_size{_minus_2,_minus_3,_diff_max_min}` fields,
112//! `max_transform_hierarchy_depth_{inter,intra}`,
113//! `scaling_list_enabled_flag` (with the nested
114//! `sps_scaling_list_data_present_flag` / [`scaling_list::ScalingListData`]
115//! §7.3.4 block), `amp_enabled_flag`,
116//! `sample_adaptive_offset_enabled_flag`, the [`sps::PcmInfo`] block
117//! gated by `pcm_enabled_flag`, the
118//! `num_short_term_ref_pic_sets` ue(v) + per-set
119//! [`sps::ShortTermRefPicSet`] (§7.3.7, both explicit and
120//! inter-RPS-prediction forms), the
121//! `long_term_ref_pics_present_flag` block plus
122//! [`sps::LongTermRefPicEntry`] table, the
123//! `sps_temporal_mvp_enabled_flag` /
124//! `strong_intra_smoothing_enabled_flag` pair, the
125//! `vui_parameters_present_flag` gate whose §E.2.1
126//! `vui_parameters()` body is decoded into [`vui::VuiParameters`]
127//! (aspect-ratio / EXTENDED_SAR, overscan, video-signal-type +
128//! colour-description, chroma-loc, default-display-window, the
129//! `vui_timing_info` block — `u(32)` num_units_in_tick / time_scale
130//! plus the nested §E.2.3 `hrd_parameters()` call — and
131//! bitstream-restriction), and the `sps_extension_present_flag`
132//! gate whose extension body is surfaced as [`sps::OpaqueTail`].
133//! The §7.3.4 `scaling_list_data()` block — when
134//! `sps_scaling_list_data_present_flag == 1` — is parsed and the
135//! §7.4.5 `ScalingList[sizeId][matrixId][i]` coefficient arrays are
136//! derived (default tables + prediction inference); see
137//! [`scaling_list::ScalingListData`].
138//! * §6.5 [`scan`] — all four scan-order initialization processes plus
139//! the §7.4.2 [`scan::scan_order`] `ScanOrder[log2BlockSize][scanIdx]`
140//! accessor: [`scan::up_right_diagonal`] (§6.5.3, equation 6-11),
141//! [`scan::horizontal`] (§6.5.4, equation 6-12),
142//! [`scan::vertical`] (§6.5.5, equation 6-13), and
143//! [`scan::traverse`] (§6.5.6, equation 6-14, the boustrophedon
144//! raster). [`scan::scan_order`] enforces §7.4.2's populated ranges
145//! (`log2BlockSize` 0..=3 for diagonal / horizontal / vertical, 2..=5
146//! for traverse). §7.4.5
147//! [`scaling_list::ScalingListData::scaling_factors`] expands the
148//! flat scaling lists into the two-dimensional
149//! `ScalingFactor[sizeId][matrixId][x][y]` quantization matrices
150//! (equations 7-44..7-51: the diagonal scatter, the 2x / 4x block
151//! replication, the DC `[0][0]` override, and the
152//! `ChromaArrayType == 3` 32x32-chroma derivation).
153//! * §7.3.2.3.1 [`pps::PicParameterSet`] — the full general
154//! `pic_parameter_set_rbsp()` body: the `pps_*_id` pair, the
155//! slice-header gates, `init_qp_minus26` (`se(v)`), the chroma QP
156//! offsets, the tiles block ([`pps::TileInfo`] — column/row counts
157//! plus the explicit `column_width_minus1[]` / `row_height_minus1[]`
158//! arrays when `uniform_spacing_flag == 0`), the
159//! deblocking-filter-control block ([`pps::DeblockingFilterControl`]),
160//! `lists_modification_present_flag`,
161//! `log2_parallel_merge_level_minus2`, and the
162//! `pps_extension_present_flag` gate. When
163//! `pps_extension_present_flag == 1` the eight bits of typed
164//! extension flags are decoded into [`pps::PpsExtensionFlags`]
165//! (`pps_range_extension_flag`, `pps_multilayer_extension_flag`,
166//! `pps_3d_extension_flag`, `pps_scc_extension_flag`, and the
167//! reserved `pps_extension_4bits`); any extension body whose flag
168//! is set is surfaced as a shared [`sps::OpaqueTail`] starting at
169//! the first body's bit position. When
170//! `pps_scaling_list_data_present_flag == 1` the §7.3.4
171//! `scaling_list_data()` block is parsed into
172//! [`scaling_list::ScalingListData`]. The §7.4.3.3.1 inference rules
173//! are applied so absent conditional fields carry their effective
174//! value.
175//! * §7.3.6.1 [`slice::SliceSegmentHeader`] — the
176//! `slice_segment_header()` parse for an independent slice segment,
177//! taking the activated SPS + PPS as context (the
178//! `slice_segment_address` and `slice_pic_order_cnt_lsb` widths plus
179//! the SAO / MVP / tiles gates are SPS/PPS-derived). Independent
180//! **I-slice** segments — both IDR and non-IDR — parse end to end
181//! through `byte_alignment()`, including the §7.3.6.1 non-IDR POC
182//! (`slice_pic_order_cnt_lsb`) + short-term-RPS
183//! (`short_term_ref_pic_set_sps_flag` /
184//! in-line `st_ref_pic_set(num_short_term_ref_pic_sets)` via
185//! [`sps::ShortTermRefPicSet::parse_slice_inline`] /
186//! `short_term_ref_pic_set_idx`) + long-term-RPS block (per-entry
187//! SPS-indexed vs in-slice + `delta_poc_msb_present_flag` /
188//! `delta_poc_msb_cycle_lt`, surfaced as
189//! [`slice::SliceLongTermRefPic`]). The P/B reference-list /
190//! weighted-prediction sub-structures are still surfaced as an
191//! [`sps::OpaqueTail`]. The §7.4.7.1 inference rules are applied to
192//! absent fields.
193//! * §7.3.6.2 [`slice::RefPicListsModification`] — the
194//! `ref_pic_lists_modification()` syntax structure as a standalone
195//! parser. The parser walks the
196//! `ref_pic_list_modification_flag_lX` `u(1)` gates and the
197//! `list_entry_lX[]` `u(v)` loops (each entry
198//! `Ceil( Log2( NumPicTotalCurr ) )` bits wide and range-checked
199//! per §7.4.7.2); the implicit `RefPicListTempX` derivation of
200//! §8.3.4 stays the consumer's responsibility.
201//! * §7.4.7.2 [`slice::NumPicTotalCurrInputs`] — the
202//! `NumPicTotalCurr` derivation (equation 7-57) as a small typed
203//! builder taking the per-position `UsedByCurrPicS0` /
204//! `UsedByCurrPicS1` / `UsedByCurrPicLt` flags from the active
205//! short-term RPS + the slice's long-term ref list and the
206//! `pps_curr_pic_ref_enabled_flag` closing-clause flag, returning
207//! the typed `NumPicTotalCurr: u32`. A
208//! [`slice::NumPicTotalCurrInputs::from_explicit_short_term_rps`]
209//! convenience constructor sources `S0` / `S1` straight off an
210//! explicit-form [`sps::ShortTermRefPicSet`]; the
211//! inter-RPS-prediction form needs the §7.4.8 derivation to run
212//! first.
213//! [`slice::SliceLongTermRefPic::used_by_curr_pic_lt`] resolves
214//! each long-term entry's `UsedByCurrPicLt[i]` per §7.4.7.1
215//! (SPS-table lookup for SPS-resident entries, direct flag for
216//! in-slice entries). The F.7.4.7.2 multilayer-extension form
217//! (equation F-56) is reachable through
218//! [`slice::NumPicTotalCurrInputs::with_multilayer_extension`].
219//! * §7.3.6.3 [`slice::PredWeightTable`] — the
220//! `pred_weight_table()` syntax structure as a standalone parser.
221//! The parser walks the `luma_log2_weight_denom` /
222//! `delta_chroma_log2_weight_denom` denominators, the two flag passes
223//! (`luma_weight_lX_flag[i]` + `chroma_weight_lX_flag[i]`), and the
224//! per-reference delta block (`delta_luma_weight_lX[i]` /
225//! `luma_offset_lX[i]` / `delta_chroma_weight_lX[i][j]` /
226//! `delta_chroma_offset_lX[i][j]`), applying the §7.4.7.3 range
227//! bounds + the per-i §7.3.6.3 outer-gate (`pic_layer_id !=
228//! nuh_layer_id || PicOrderCnt(RefPicListX[i]) !=
229//! PicOrderCnt(CurrPic)`) decision supplied by the caller, the
230//! `ChromaLog2WeightDenom ∈ 0..=7` derived range, and the
231//! `sumWeightLXFlags ≤ 24` conformance cap.
232//! [`slice::PredWeightTable::luma_weight_l0`] /
233//! [`slice::PredWeightTable::chroma_weight_l0`] (mirrored for L1)
234//! resolve each derived `LumaWeightLX[i]` /
235//! `ChromaWeightLX[i][j]`; [`slice::PredWeightTable::chroma_offset_l0`]
236//! (mirrored) applies equation 7-58 for `ChromaOffsetLX[i][j]`.
237//!
238//! See [`nal`] for the byte-stream walker entry points, [`vps`] for
239//! the parsed VPS structure, [`sps`] for the parsed SPS, [`pps`]
240//! for the parsed PPS, and [`crate::slice`] for the parsed slice
241//! header.
242
243#![warn(missing_debug_implementations)]
244
245use oxideav_core::RuntimeContext;
246
247// internal — exposed for tests/fuzz; not part of the stable API
248#[doc(hidden)]
249pub mod availability;
250// internal — exposed for tests/fuzz; not part of the stable API
251#[doc(hidden)]
252pub mod binarization;
253// internal — exposed for tests/fuzz; not part of the stable API
254#[doc(hidden)]
255pub mod bitreader;
256// internal — exposed for tests/fuzz; not part of the stable API
257#[doc(hidden)]
258pub mod cabac;
259// internal — exposed for tests/fuzz; not part of the stable API
260#[doc(hidden)]
261pub mod ctx_init;
262// internal — exposed for tests/fuzz; not part of the stable API
263#[doc(hidden)]
264pub mod deblock;
265// internal — exposed for tests/fuzz; not part of the stable API
266#[doc(hidden)]
267pub mod decode;
268pub mod decoder;
269// internal — exposed for tests/fuzz; not part of the stable API
270#[doc(hidden)]
271pub mod dpb;
272pub mod encoder;
273// internal — exposed for tests/fuzz; not part of the stable API
274#[doc(hidden)]
275pub mod hrd;
276pub mod hvcc;
277// internal — exposed for tests/fuzz; not part of the stable API
278#[doc(hidden)]
279pub mod inter_pred;
280// internal — exposed for tests/fuzz; not part of the stable API
281#[doc(hidden)]
282pub mod inter_recon;
283// internal — exposed for tests/fuzz; not part of the stable API
284#[doc(hidden)]
285pub mod intra_mode_field;
286// internal — exposed for tests/fuzz; not part of the stable API
287#[doc(hidden)]
288pub mod intra_pred;
289// internal — exposed for tests/fuzz; not part of the stable API
290#[doc(hidden)]
291pub mod motion;
292pub mod nal;
293// internal — exposed for tests/fuzz; not part of the stable API
294#[doc(hidden)]
295pub mod palette;
296pub mod picture;
297// internal — exposed for tests/fuzz; not part of the stable API
298#[doc(hidden)]
299pub mod poc;
300// internal — exposed for tests/fuzz; not part of the stable API
301#[doc(hidden)]
302pub mod pps;
303// internal — exposed for tests/fuzz; not part of the stable API
304#[doc(hidden)]
305pub mod pu_mv;
306// internal — exposed for tests/fuzz; not part of the stable API
307#[doc(hidden)]
308pub mod recon;
309// internal — exposed for tests/fuzz; not part of the stable API
310#[doc(hidden)]
311pub mod residual;
312// internal — exposed for tests/fuzz; not part of the stable API
313#[doc(hidden)]
314pub mod sao;
315// internal — exposed for tests/fuzz; not part of the stable API
316#[doc(hidden)]
317pub mod scaling_list;
318// internal — exposed for tests/fuzz; not part of the stable API
319#[doc(hidden)]
320pub mod scan;
321// internal — exposed for tests/fuzz; not part of the stable API
322#[doc(hidden)]
323pub mod sei;
324pub mod sequence;
325// internal — exposed for tests/fuzz; not part of the stable API
326#[doc(hidden)]
327pub mod slice;
328// internal — exposed for tests/fuzz; not part of the stable API
329#[doc(hidden)]
330pub mod slice_data;
331// internal — exposed for tests/fuzz; not part of the stable API
332#[doc(hidden)]
333pub mod sps;
334// internal — exposed for tests/fuzz; not part of the stable API
335#[doc(hidden)]
336pub mod transform;
337// internal — exposed for tests/fuzz; not part of the stable API
338#[doc(hidden)]
339pub mod transform_tree;
340// internal — exposed for tests/fuzz; not part of the stable API
341#[doc(hidden)]
342pub mod transform_unit;
343// internal — exposed for tests/fuzz; not part of the stable API
344#[doc(hidden)]
345pub mod vps;
346// internal — exposed for tests/fuzz; not part of the stable API
347#[doc(hidden)]
348pub mod vui;
349
350// internal — exposed for tests/fuzz; not part of the stable API
351#[doc(hidden)]
352pub use availability::{AvailabilityError, PictureTiling, TilingParams};
353// internal — exposed for tests/fuzz; not part of the stable API
354#[doc(hidden)]
355pub use bitreader::{BitReader, BitReaderError};
356// internal — exposed for tests/fuzz; not part of the stable API
357#[doc(hidden)]
358pub use cabac::{init_type, CabacEngine, CabacError, ContextModel};
359// internal — exposed for tests/fuzz; not part of the stable API
360#[doc(hidden)]
361pub use ctx_init::SliceContexts;
362// internal — exposed for tests/fuzz; not part of the stable API
363#[doc(hidden)]
364pub use deblock::{
365 deblock_picture, deblock_picture_full, derive_boundary_strength, derive_edge_flags,
366 filter_cu_edges, filter_cu_edges_full, BoundaryStrength, DeblockCu, DeblockCuDesc,
367 DeblockCuParams, EdgeFlags, EdgeType, NoFilterMap, TransformSplit,
368};
369// internal — exposed for tests/fuzz; not part of the stable API
370#[doc(hidden)]
371pub use decode::{PictureHeaderInfo, PictureRefState, PictureSequenceState, SliceRefParams};
372pub use decoder::{make_decoder, H265Decoder};
373// internal — exposed for tests/fuzz; not part of the stable API
374#[doc(hidden)]
375pub use dpb::{
376 build_rps_poc_lists, no_backward_pred_flag, select_col_pic, Dpb, DpbEntry, LongTermEntry,
377 Marking, RefPicListParams, RefPicLists, ResolvedRps, RpsPocLists,
378};
379pub use encoder::{make_encoder, H265Encoder, H265PcmEncoder};
380pub use hrd::HrdError;
381// internal — exposed for tests/fuzz; not part of the stable API
382#[doc(hidden)]
383pub use hrd::{
384 CpbEntry, HrdCommonInfo, HrdParameters, SubLayerHrd, SubLayerHrdParameters, VpsHrdEntry,
385 HEVC_MAX_CPB_CNT, HEVC_MAX_ELEMENTAL_DURATION_IN_TC_MINUS1,
386};
387pub use hvcc::{
388 extradata_is_hvcc, nal_unit_from_coded, parse_hvcc, split_length_prefixed, HvccError,
389 HvccRecord,
390};
391// internal — exposed for tests/fuzz; not part of the stable API
392#[doc(hidden)]
393pub use inter_pred::{
394 default_weighted_pred, explicit_weighted_pred, interp_chroma_block, interp_luma_block,
395 predict_inter_pu, predict_inter_pu_weighted, InterPredError, InterPredGeometry,
396 InterPrediction, ListPrediction, MotionVector, PuWeights, RefPlane, WpListWeights,
397};
398// internal — exposed for tests/fuzz; not part of the stable API
399#[doc(hidden)]
400pub use inter_recon::SliceWpTables;
401// internal — exposed for tests/fuzz; not part of the stable API
402#[doc(hidden)]
403pub use intra_mode_field::{IntraModeField, Neighbour, MIN_BLOCK_LOG2, MIN_BLOCK_SIZE};
404// internal — exposed for tests/fuzz; not part of the stable API
405#[doc(hidden)]
406pub use motion::{
407 append_combined_bi_candidates, append_zero_merge_candidates, build_merge_candidate,
408 derive_chroma_mv, derive_mvp_candidate, derive_spatial_merge_candidates, derive_temporal_mv,
409 reconstruct_mv, MergeCandidate, MergeListParams, MotionCell, MotionField, Mv, MvpContext,
410 NeighbourPu, PartitionContext, RefPicId, SpatialMergeCandidates, SpatialMergeNeighbours,
411 TemporalMvContext,
412};
413pub use nal::{collect_nal_units, NalError, NalHeader, NalIter, NalUnit};
414pub use picture::{clip1, sub_wh_c, Picture, Plane};
415// internal — exposed for tests/fuzz; not part of the stable API
416#[doc(hidden)]
417pub use poc::{diff_pic_order_cnt, NalKind, PicOrderCnt, PocState};
418pub use pps::PpsError;
419// internal — exposed for tests/fuzz; not part of the stable API
420#[doc(hidden)]
421pub use pps::{
422 ChromaQpOffsetListEntry, DeblockingFilterControl, PicParameterSet, PpsRangeExtension, TileInfo,
423};
424// internal — exposed for tests/fuzz; not part of the stable API
425#[doc(hidden)]
426pub use pu_mv::{
427 pu_partitions, resolve_cu_motion, resolve_pu_motion, InterCuDesc, PartMode as PuPartMode,
428 PuGeometry, PuMotion, PuMvContext, PuRect,
429};
430pub use recon::ReconError;
431// internal — exposed for tests/fuzz; not part of the stable API
432#[doc(hidden)]
433pub use recon::{
434 build_slice_addr_map, reconstruct_inter_pu, reconstruct_inter_pu_weighted,
435 reconstruct_intra_ctu, reconstruct_intra_ctu_ctx, reconstruct_intra_picture,
436 IntraPictureParams, PlacedCtu, ReconCtx, ReconParams, ResolvedList, SliceSegmentBoundary,
437};
438// internal — exposed for tests/fuzz; not part of the stable API
439#[doc(hidden)]
440pub use sao::{
441 apply_sao_ctb, apply_sao_picture, apply_sao_picture_full, ResolvedSao, ResolvedSaoComponent,
442};
443// internal — exposed for tests/fuzz; not part of the stable API
444#[doc(hidden)]
445pub use scaling_list::{
446 ScalingFactorMatrix, ScalingFactors, ScalingListData, ScalingListError, ScalingListMatrix,
447 MAX_COEF_NUM, NUM_MATRIX_IDS, NUM_SIZE_IDS,
448};
449// internal — exposed for tests/fuzz; not part of the stable API
450#[doc(hidden)]
451pub use scan::{
452 horizontal, scan_order, traverse, up_right_diagonal, vertical, ScanIdx, ScanOrderError, ScanPos,
453};
454pub use sequence::{decode_annexb_sequence, DecodedFrame, SequenceDecoder, SequenceError};
455pub use slice::SliceError;
456// internal — exposed for tests/fuzz; not part of the stable API
457#[doc(hidden)]
458pub use slice::{
459 EntryPointOffsets, NumPicTotalCurrInputs, PredWeightEntry, PredWeightTable,
460 PredWeightTableInputs, RefPicListsModification, SliceDeblocking, SliceLongTermRefPic,
461 SliceLongTermRefPicSource, SliceSegmentHeader, SliceType, BLA_W_LP, IDR_N_LP, IDR_W_RADL,
462 RSV_IRAP_VCL23,
463};
464// internal — exposed for tests/fuzz; not part of the stable API
465#[doc(hidden)]
466pub use slice_data::{
467 decode_coding_quadtree, decode_coding_tree_unit, decode_coding_tree_unit_in_picture,
468 decode_sao, CodingQuadtree, CodingTreeUnit, CodingUnit, IntraLumaMode, PcmSamples,
469 PictureParseState, PredictionUnit, SaoComponent, SaoCtbParams, SliceDataParams,
470};
471pub use sps::{ShortTermRefPicSetMaterializeError, SpsError};
472// internal — exposed for tests/fuzz; not part of the stable API
473#[doc(hidden)]
474pub use sps::{
475 ConformanceWindow, LongTermRefPicEntry, MaterializedShortTermRefPicSet, OpaqueTail, PcmInfo,
476 SeqParameterSet, ShortTermRefPicSet, SpsExtensionFlags, SpsRangeExtension,
477 HEVC_MAX_NUM_LONG_TERM_RPS, HEVC_MAX_NUM_SHORT_TERM_RPS, HEVC_MAX_RPS_PICS,
478};
479// internal — exposed for tests/fuzz; not part of the stable API
480#[doc(hidden)]
481pub use transform_tree::{decode_transform_tree, TransformTree, TransformTreeParams};
482// internal — exposed for tests/fuzz; not part of the stable API
483#[doc(hidden)]
484pub use transform_unit::{
485 decode_transform_unit, CuPredMode, QuantGroupState, TransformUnit, TransformUnitParams,
486};
487pub use vps::VpsError;
488// internal — exposed for tests/fuzz; not part of the stable API
489#[doc(hidden)]
490pub use vps::{
491 HevcVps, LayerIdInclusionRow, ProfileTierLevel, SubLayerOrderingInfo, VpsTimingInfo,
492 HEVC_MAX_SUB_LAYERS, HEVC_VPS_MAX_NUM_LAYERS, HEVC_VPS_MAX_NUM_LAYER_SETS,
493};
494pub use vui::VuiError;
495// internal — exposed for tests/fuzz; not part of the stable API
496#[doc(hidden)]
497pub use vui::{
498 BitstreamRestriction, ColourDescription, DefaultDisplayWindow, VideoSignalType, VuiParameters,
499 VuiTimingInfo, EXTENDED_SAR,
500};
501
502/// Crate-local error type for the structural utilities (the NAL
503/// walker and parameter-set parsers surface their own [`NalError`] /
504/// [`VpsError`] types directly; the decode drivers use
505/// [`sequence::SequenceError`] and the registry decoder maps into
506/// [`oxideav_core::Error`]).
507#[derive(Debug, Clone, Copy, PartialEq, Eq)]
508pub enum Error {
509 /// The requested functionality is not implemented (the encoder,
510 /// and the remaining decoder gaps listed in `README.md`).
511 NotImplemented,
512 /// A NAL-walker error surfaced through the top-level entry
513 /// points.
514 Nal(NalError),
515 /// A VPS-parser error surfaced through the top-level entry
516 /// points.
517 Vps(VpsError),
518 /// An SPS-parser error surfaced through the top-level entry
519 /// points.
520 Sps(SpsError),
521 /// A PPS-parser error surfaced through the top-level entry
522 /// points.
523 Pps(PpsError),
524 /// A slice-segment-header-parser error surfaced through the
525 /// top-level entry points.
526 Slice(SliceError),
527 /// An `hrd_parameters()` parser error surfaced through the
528 /// top-level entry points.
529 Hrd(HrdError),
530 /// A `vui_parameters()` parser error surfaced through the
531 /// top-level entry points.
532 Vui(VuiError),
533}
534
535impl core::fmt::Display for Error {
536 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
537 match self {
538 Self::NotImplemented => f.write_str("oxideav-h265: decoder/encoder not wired up yet"),
539 Self::Nal(e) => write!(f, "oxideav-h265 NAL error: {e}"),
540 Self::Vps(e) => write!(f, "oxideav-h265 VPS error: {e}"),
541 Self::Sps(e) => write!(f, "oxideav-h265 SPS error: {e}"),
542 Self::Pps(e) => write!(f, "oxideav-h265 PPS error: {e}"),
543 Self::Slice(e) => write!(f, "oxideav-h265 slice header error: {e}"),
544 Self::Hrd(e) => write!(f, "oxideav-h265 hrd error: {e}"),
545 Self::Vui(e) => write!(f, "oxideav-h265 vui error: {e}"),
546 }
547 }
548}
549
550impl std::error::Error for Error {}
551
552impl From<NalError> for Error {
553 fn from(e: NalError) -> Self {
554 Self::Nal(e)
555 }
556}
557
558impl From<VpsError> for Error {
559 fn from(e: VpsError) -> Self {
560 Self::Vps(e)
561 }
562}
563
564impl From<SpsError> for Error {
565 fn from(e: SpsError) -> Self {
566 Self::Sps(e)
567 }
568}
569
570impl From<PpsError> for Error {
571 fn from(e: PpsError) -> Self {
572 Self::Pps(e)
573 }
574}
575
576impl From<SliceError> for Error {
577 fn from(e: SliceError) -> Self {
578 Self::Slice(e)
579 }
580}
581
582impl From<HrdError> for Error {
583 fn from(e: HrdError) -> Self {
584 Self::Hrd(e)
585 }
586}
587
588impl From<VuiError> for Error {
589 fn from(e: VuiError) -> Self {
590 Self::Vui(e)
591 }
592}
593
594/// Codec registration: the software H.265 / HEVC decoder under the
595/// `"h265"` id (aliased `"hevc"`), claiming the common container tags
596/// (`hvc1` / `hev1` sample entries, the MP4 ObjectTypeIndication for
597/// HEVC, and the `HEVC` FourCC).
598pub fn register(ctx: &mut RuntimeContext) {
599 use oxideav_core::{CodecInfo, CodecTag};
600 for id in ["h265", "hevc"] {
601 ctx.codecs.register(
602 CodecInfo::new(id.into())
603 .decoder(decoder::make_decoder)
604 .encoder(encoder::make_encoder)
605 .tags([
606 CodecTag::fourcc(b"hvc1"),
607 CodecTag::fourcc(b"hev1"),
608 CodecTag::fourcc(b"HEVC"),
609 CodecTag::mp4_object_type(0x23),
610 CodecTag::matroska("V_MPEGH/ISO/HEVC"),
611 ]),
612 );
613 }
614}
615
616oxideav_core::register!("h265", register);